mirror of https://github.com/matrix-org/go-neb.git
Browse Source
Move some of the client and crypto logic to a new BotClient type
Move some of the client and crypto logic to a new BotClient type
Signed-off-by: Nikos Filippakis <me@nfil.dev>pull/324/head
No known key found for this signature in database
GPG Key ID: 7110E4356101F017
6 changed files with 255 additions and 106 deletions
-
103clients/bot_client.go
-
171clients/clients.go
-
3clients/clients_test.go
-
28clients/crypto_logger.go
-
54clients/state_store.go
-
2services/jira/jira.go
@ -0,0 +1,103 @@ |
|||
package clients |
|||
|
|||
import ( |
|||
"github.com/matrix-org/go-neb/api" |
|||
"github.com/matrix-org/go-neb/matrix" |
|||
log "github.com/sirupsen/logrus" |
|||
"maunium.net/go/mautrix" |
|||
"maunium.net/go/mautrix/crypto" |
|||
mevt "maunium.net/go/mautrix/event" |
|||
"maunium.net/go/mautrix/id" |
|||
) |
|||
|
|||
// BotClient represents one of the bot's sessions, with a specific User and Device ID.
|
|||
// It can be used for sending messages and retrieving information about the rooms that
|
|||
// the client has joined.
|
|||
type BotClient struct { |
|||
config api.ClientConfig |
|||
client *mautrix.Client |
|||
olmMachine *crypto.OlmMachine |
|||
stateStore *NebStateStore |
|||
} |
|||
|
|||
// InitOlmMachine initializes a BotClient's internal OlmMachine given a client object and a Neb store,
|
|||
// which will be used to store room information.
|
|||
func (botClient *BotClient) InitOlmMachine(client *mautrix.Client, nebStore *matrix.NEBStore) error { |
|||
gobStore, err := crypto.NewGobStore("crypto.gob") |
|||
if err != nil { |
|||
return err |
|||
} |
|||
|
|||
botClient.stateStore = &NebStateStore{&nebStore.InMemoryStore} |
|||
olmMachine := crypto.NewOlmMachine(client, CryptoMachineLogger{}, gobStore, botClient.stateStore) |
|||
if err = olmMachine.Load(); err != nil { |
|||
return nil |
|||
} |
|||
botClient.olmMachine = olmMachine |
|||
|
|||
return nil |
|||
} |
|||
|
|||
// Register registers a BotClient's Sync and StateMember event callbacks to update its internal state
|
|||
// when new events arrive.
|
|||
func (botClient *BotClient) Register(syncer mautrix.ExtensibleSyncer) { |
|||
syncer.OnEventType(mevt.StateMember, func(_ mautrix.EventSource, evt *mevt.Event) { |
|||
botClient.olmMachine.HandleMemberEvent(evt) |
|||
}) |
|||
syncer.OnSync(botClient.syncCallback) |
|||
} |
|||
|
|||
func (botClient *BotClient) syncCallback(resp *mautrix.RespSync, since string) bool { |
|||
botClient.stateStore.UpdateStateStore(resp) |
|||
botClient.olmMachine.ProcessSyncResponse(resp, since) |
|||
if err := botClient.olmMachine.CryptoStore.Flush(); err != nil { |
|||
log.WithError(err).Error("Could not flush crypto store") |
|||
} |
|||
return true |
|||
} |
|||
|
|||
// DecryptMegolmEvent attempts to decrypt an incoming m.room.encrypted message using the session information
|
|||
// already present in the OlmMachine. The corresponding decrypted event is then returned.
|
|||
// If it fails, usually because the session is not known, an error is returned.
|
|||
func (botClient *BotClient) DecryptMegolmEvent(evt *mevt.Event) (*mevt.Event, error) { |
|||
return botClient.olmMachine.DecryptMegolmEvent(evt) |
|||
} |
|||
|
|||
// SendMessageEvent sends the given content to the given room ID using this BotClient as a message event.
|
|||
// If the target room has enabled encryption, a megolm session is created if one doesn't already exist
|
|||
// and the message is sent after being encrypted.
|
|||
func (botClient *BotClient) SendMessageEvent(content interface{}, roomID id.RoomID) error { |
|||
evtType := mevt.EventMessage |
|||
olmMachine := botClient.olmMachine |
|||
if olmMachine.StateStore.IsEncrypted(roomID) { |
|||
// Check if there is already a megolm session
|
|||
if sess, err := olmMachine.CryptoStore.GetOutboundGroupSession(roomID); err != nil { |
|||
return err |
|||
} else if sess == nil || sess.Expired() || !sess.Shared { |
|||
// No error but valid, shared session does not exist
|
|||
membs, err := botClient.client.JoinedMembers(roomID) |
|||
if err != nil { |
|||
return err |
|||
} |
|||
memberIDs := make([]id.UserID, 0, len(membs.Joined)) |
|||
for member := range membs.Joined { |
|||
memberIDs = append(memberIDs, member) |
|||
} |
|||
// Share group session with room members
|
|||
if err = olmMachine.ShareGroupSession(roomID, memberIDs); err != nil { |
|||
return err |
|||
} |
|||
} |
|||
msgContent := mevt.Content{Parsed: content} |
|||
enc, err := olmMachine.EncryptMegolmEvent(roomID, mevt.EventMessage, msgContent) |
|||
if err != nil { |
|||
return err |
|||
} |
|||
content = enc |
|||
evtType = mevt.EventEncrypted |
|||
} |
|||
if _, err := botClient.client.SendMessageEvent(roomID, evtType, content); err != nil { |
|||
return err |
|||
} |
|||
return nil |
|||
} |
@ -0,0 +1,28 @@ |
|||
package clients |
|||
|
|||
import ( |
|||
log "github.com/sirupsen/logrus" |
|||
) |
|||
|
|||
// CryptoMachineLogger wraps around the usual logger, implementing the Logger interface needed by OlmMachine.
|
|||
type CryptoMachineLogger struct{} |
|||
|
|||
// Error formats and logs an error message.
|
|||
func (CryptoMachineLogger) Error(message string, args ...interface{}) { |
|||
log.Errorf(message, args...) |
|||
} |
|||
|
|||
// Warn formats and logs a warning message.
|
|||
func (CryptoMachineLogger) Warn(message string, args ...interface{}) { |
|||
log.Warnf(message, args...) |
|||
} |
|||
|
|||
// Debug formats and logs a debug message.
|
|||
func (CryptoMachineLogger) Debug(message string, args ...interface{}) { |
|||
log.Debugf(message, args...) |
|||
} |
|||
|
|||
// Trace formats and logs a trace message.
|
|||
func (CryptoMachineLogger) Trace(message string, args ...interface{}) { |
|||
log.Tracef(message, args...) |
|||
} |
@ -0,0 +1,54 @@ |
|||
package clients |
|||
|
|||
import ( |
|||
"maunium.net/go/mautrix" |
|||
"maunium.net/go/mautrix/event" |
|||
"maunium.net/go/mautrix/id" |
|||
) |
|||
|
|||
// NebStateStore implements the StateStore interface for OlmMachine.
|
|||
// It is used to determine which rooms are encrypted and which rooms are shared with a user.
|
|||
// The state is updated by /sync responses.
|
|||
type NebStateStore struct { |
|||
Storer *mautrix.InMemoryStore |
|||
} |
|||
|
|||
// IsEncrypted returns whether a room has been encrypted.
|
|||
func (ss *NebStateStore) IsEncrypted(roomID id.RoomID) bool { |
|||
room := ss.Storer.LoadRoom(roomID) |
|||
if room == nil { |
|||
return false |
|||
} |
|||
_, ok := room.State[event.StateEncryption] |
|||
return ok |
|||
} |
|||
|
|||
// FindSharedRooms returns a list of room IDs that the given user ID is also a member of.
|
|||
func (ss *NebStateStore) FindSharedRooms(userID id.UserID) []id.RoomID { |
|||
sharedRooms := make([]id.RoomID, 0) |
|||
for roomID, room := range ss.Storer.Rooms { |
|||
if room.GetMembershipState(userID) != event.MembershipLeave { |
|||
sharedRooms = append(sharedRooms, roomID) |
|||
} |
|||
} |
|||
return sharedRooms |
|||
} |
|||
|
|||
// UpdateStateStore updates the internal state of NebStateStore from a /sync response.
|
|||
func (ss *NebStateStore) UpdateStateStore(resp *mautrix.RespSync) { |
|||
for roomID, evts := range resp.Rooms.Join { |
|||
room := ss.Storer.LoadRoom(roomID) |
|||
if room == nil { |
|||
room = mautrix.NewRoom(roomID) |
|||
ss.Storer.SaveRoom(room) |
|||
} |
|||
for _, i := range evts.State.Events { |
|||
room.UpdateState(i) |
|||
} |
|||
for _, i := range evts.Timeline.Events { |
|||
if i.Type.IsState() { |
|||
room.UpdateState(i) |
|||
} |
|||
} |
|||
} |
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue