mirror of
https://github.com/hrfee/jfa-go.git
synced 2024-12-22 17:10:10 +00:00
Harvey Tindall
aa2891fc87
also some more attempts at fixing it, so far all i've found is that if we don't delete the cryptoStore, the matrix client also gets the same error we do if it send s a message to us (no session with given ID found).
225 lines
6.1 KiB
Go
225 lines
6.1 KiB
Go
// +build e2ee
|
|
|
|
package main
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"maunium.net/go/mautrix"
|
|
"maunium.net/go/mautrix/crypto"
|
|
"maunium.net/go/mautrix/event"
|
|
"maunium.net/go/mautrix/id"
|
|
)
|
|
|
|
type Crypto struct {
|
|
cryptoStore *crypto.GobStore
|
|
olm *crypto.OlmMachine
|
|
}
|
|
|
|
func MatrixE2EE() bool { return true }
|
|
|
|
type stateStore struct {
|
|
isEncrypted *map[id.RoomID]bool
|
|
}
|
|
|
|
func (m *stateStore) IsEncrypted(roomID id.RoomID) bool {
|
|
// encrypted, ok := (*m.isEncrypted)[roomID]
|
|
// return ok && encrypted
|
|
return true
|
|
}
|
|
|
|
func (m *stateStore) GetEncryptionEvent(roomID id.RoomID) *event.EncryptionEventContent {
|
|
return &event.EncryptionEventContent{
|
|
Algorithm: id.AlgorithmMegolmV1,
|
|
RotationPeriodMillis: 7 * 24 * 60 * 60 * 1000,
|
|
RotationPeriodMessages: 100,
|
|
}
|
|
}
|
|
|
|
// Users are assumed to only have one common channel with the bot, so we can stub this out.
|
|
func (m *stateStore) FindSharedRooms(userID id.UserID) []id.RoomID {
|
|
// for _, user := range m.app.storage.matrix {
|
|
// if id.UserID(user.UserID) == userID {
|
|
// return []id.RoomID{id.RoomID(user.RoomID)}
|
|
// }
|
|
// }
|
|
return []id.RoomID{}
|
|
}
|
|
|
|
func (d *MatrixDaemon) getUserIDs(roomID id.RoomID) (list []id.UserID, err error) {
|
|
members, err := d.bot.JoinedMembers(roomID)
|
|
if err != nil {
|
|
return
|
|
}
|
|
list = make([]id.UserID, len(members.Joined))
|
|
i := 0
|
|
for id := range members.Joined {
|
|
list[i] = id
|
|
i++
|
|
}
|
|
return
|
|
}
|
|
|
|
type olmLogger struct {
|
|
app *appContext
|
|
}
|
|
|
|
func (o olmLogger) Error(message string, args ...interface{}) {
|
|
o.app.err.Printf("OLM: "+message+"\n", args)
|
|
}
|
|
|
|
func (o olmLogger) Warn(message string, args ...interface{}) {
|
|
o.app.info.Printf("OLM: "+message+"\n", args)
|
|
}
|
|
|
|
func (o olmLogger) Debug(message string, args ...interface{}) {
|
|
o.app.debug.Printf("OLM: "+message+"\n", args)
|
|
}
|
|
|
|
func (o olmLogger) Trace(message string, args ...interface{}) {
|
|
if strings.HasPrefix(message, "Got membership state event") {
|
|
return
|
|
}
|
|
o.app.debug.Printf("OLM [TRACE]: "+message+"\n", args)
|
|
}
|
|
|
|
func InitMatrixCrypto(d *MatrixDaemon) (err error) {
|
|
d.Encryption = d.app.config.Section("matrix").Key("encryption").MustBool(false)
|
|
if !d.Encryption {
|
|
return
|
|
}
|
|
for _, user := range d.app.storage.matrix {
|
|
d.isEncrypted[id.RoomID(user.RoomID)] = user.Encrypted
|
|
}
|
|
dbPath := d.app.config.Section("files").Key("matrix_sql").String()
|
|
// If the db is maintained after restart, element reports "The secure channel with the sender was corrupted" when sending a message from the bot.
|
|
// This obviously isn't right, but it seems to work.
|
|
// Since its not really used anyway, just use the deprecated GobStore. This reduces cgo usage anyway.
|
|
var cryptoStore *crypto.GobStore
|
|
cryptoStore, err = crypto.NewGobStore(dbPath)
|
|
// d.db, err = sql.Open("sqlite3", dbPath)
|
|
if err != nil {
|
|
return
|
|
}
|
|
olmLog := &olmLogger{d.app}
|
|
// deviceID := "jfa-go" + commit
|
|
// cryptoStore := crypto.NewSQLCryptoStore(d.db, "sqlite3", string(d.userID)+deviceID, id.DeviceID(deviceID), []byte("jfa-go"), olmLog)
|
|
// err = cryptoStore.CreateTables()
|
|
// if err != nil {
|
|
// return
|
|
// }
|
|
olm := crypto.NewOlmMachine(d.bot, olmLog, cryptoStore, &stateStore{&d.isEncrypted})
|
|
olm.AllowUnverifiedDevices = true
|
|
err = olm.Load()
|
|
if err != nil {
|
|
return
|
|
}
|
|
d.crypto = Crypto{
|
|
cryptoStore: cryptoStore,
|
|
olm: olm,
|
|
}
|
|
return
|
|
}
|
|
|
|
func HandleSyncerCrypto(startTime int64, d *MatrixDaemon, syncer *mautrix.DefaultSyncer) {
|
|
if !d.Encryption {
|
|
return
|
|
}
|
|
syncer.OnSync(func(resp *mautrix.RespSync, since string) bool {
|
|
d.crypto.olm.ProcessSyncResponse(resp, since)
|
|
return true
|
|
})
|
|
syncer.OnEventType(event.StateMember, func(source mautrix.EventSource, evt *event.Event) {
|
|
d.crypto.olm.HandleMemberEvent(evt)
|
|
// if evt.Content.AsMember().Membership != event.MembershipJoin {
|
|
// return
|
|
// }
|
|
// userIDs, err := d.getUserIDs(evt.RoomID)
|
|
// if err != nil || len(userIDs) < 2 {
|
|
// fmt.Println("FS", err)
|
|
// return
|
|
// }
|
|
// err = d.crypto.olm.ShareGroupSession(evt.RoomID, userIDs)
|
|
// if err != nil {
|
|
// fmt.Println("FS", err)
|
|
// return
|
|
// }
|
|
})
|
|
syncer.OnEventType(event.EventEncrypted, func(source mautrix.EventSource, evt *event.Event) {
|
|
if evt.Timestamp < startTime {
|
|
return
|
|
}
|
|
decrypted, err := d.crypto.olm.DecryptMegolmEvent(evt)
|
|
// if strings.Contains(err.Error(), crypto.NoSessionFound.Error()) {
|
|
// d.app.err.Printf("Failed to decrypt Matrix message: no session found")
|
|
// return
|
|
// }
|
|
if err != nil {
|
|
d.app.err.Printf("Failed to decrypt Matrix message: %v", err)
|
|
return
|
|
}
|
|
d.handleMessage(source, decrypted)
|
|
})
|
|
}
|
|
|
|
func CryptoShutdown(d *MatrixDaemon) {
|
|
if d.Encryption {
|
|
d.crypto.olm.FlushStore()
|
|
}
|
|
}
|
|
|
|
func EncryptRoom(d *MatrixDaemon, room *mautrix.RespCreateRoom, userID id.UserID) (encrypted bool) {
|
|
if !d.Encryption {
|
|
return
|
|
}
|
|
_, err := d.bot.SendStateEvent(room.RoomID, event.StateEncryption, "", &event.EncryptionEventContent{
|
|
Algorithm: id.AlgorithmMegolmV1,
|
|
RotationPeriodMillis: 7 * 24 * 60 * 60 * 1000,
|
|
RotationPeriodMessages: 100,
|
|
})
|
|
if err == nil {
|
|
encrypted = true
|
|
} else {
|
|
d.app.debug.Printf("Matrix: Failed to enable encryption in room: %v", err)
|
|
return
|
|
}
|
|
d.isEncrypted[room.RoomID] = encrypted
|
|
var userIDs []id.UserID
|
|
userIDs, err = d.getUserIDs(room.RoomID)
|
|
if err != nil {
|
|
return
|
|
}
|
|
userIDs = append(userIDs, userID)
|
|
return
|
|
}
|
|
|
|
func SendEncrypted(d *MatrixDaemon, content *event.MessageEventContent, roomID id.RoomID) (err error) {
|
|
if !d.Encryption {
|
|
err = d.send(content, roomID)
|
|
return
|
|
}
|
|
var encrypted *event.EncryptedEventContent
|
|
encrypted, err = d.crypto.olm.EncryptMegolmEvent(roomID, event.EventMessage, content)
|
|
if err == crypto.SessionExpired || err == crypto.SessionNotShared || err == crypto.NoGroupSession {
|
|
// err = d.crypto.olm.ShareGroupSession(id.RoomID(user.RoomID), []id.UserID{id.UserID(user.UserID), d.userID})
|
|
var userIDs []id.UserID
|
|
userIDs, err = d.getUserIDs(roomID)
|
|
if err != nil {
|
|
return
|
|
}
|
|
err = d.crypto.olm.ShareGroupSession(roomID, userIDs)
|
|
if err != nil {
|
|
return
|
|
}
|
|
encrypted, err = d.crypto.olm.EncryptMegolmEvent(roomID, event.EventMessage, content)
|
|
}
|
|
if err != nil {
|
|
return
|
|
}
|
|
_, err = d.bot.SendMessageEvent(roomID, event.EventEncrypted, &event.Content{Parsed: encrypted})
|
|
if err != nil {
|
|
return
|
|
}
|
|
return
|
|
}
|