mirror of
https://github.com/hrfee/jfa-go.git
synced 2024-12-22 17:10:10 +00:00
matrix: refactor crypto sections
This commit is contained in:
parent
4c10996c09
commit
8ec4031ba3
2
.gitignore
vendored
2
.gitignore
vendored
@ -17,3 +17,5 @@ server.crt
|
|||||||
instructions-debian.txt
|
instructions-debian.txt
|
||||||
cl.md
|
cl.md
|
||||||
./telegram/
|
./telegram/
|
||||||
|
mautrix/
|
||||||
|
matacc.txt
|
||||||
|
182
matrix.go
182
matrix.go
@ -2,14 +2,10 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"database/sql"
|
|
||||||
|
|
||||||
"github.com/gomarkdown/markdown"
|
"github.com/gomarkdown/markdown"
|
||||||
_ "github.com/mattn/go-sqlite3"
|
|
||||||
gomatrix "maunium.net/go/mautrix"
|
gomatrix "maunium.net/go/mautrix"
|
||||||
"maunium.net/go/mautrix/crypto"
|
"maunium.net/go/mautrix/crypto"
|
||||||
"maunium.net/go/mautrix/event"
|
"maunium.net/go/mautrix/event"
|
||||||
@ -23,10 +19,10 @@ type MatrixDaemon struct {
|
|||||||
userID id.UserID
|
userID id.UserID
|
||||||
tokens map[string]UnverifiedUser // Map of tokens to users
|
tokens map[string]UnverifiedUser // Map of tokens to users
|
||||||
languages map[id.RoomID]string // Map of roomIDs to language codes
|
languages map[id.RoomID]string // Map of roomIDs to language codes
|
||||||
|
Encryption bool
|
||||||
isEncrypted map[id.RoomID]bool
|
isEncrypted map[id.RoomID]bool
|
||||||
cryptoStore *crypto.GobStore
|
cryptoStore *crypto.GobStore
|
||||||
olm *crypto.OlmMachine
|
olm *crypto.OlmMachine
|
||||||
db *sql.DB
|
|
||||||
app *appContext
|
app *appContext
|
||||||
start int64
|
start int64
|
||||||
}
|
}
|
||||||
@ -44,55 +40,13 @@ type MatrixUser struct {
|
|||||||
Contact bool
|
Contact bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MatrixDaemon) IsEncrypted(roomID id.RoomID) bool {
|
|
||||||
encrypted, ok := m.isEncrypted[roomID]
|
|
||||||
return ok && encrypted
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MatrixDaemon) 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 *MatrixDaemon) 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{}
|
|
||||||
}
|
|
||||||
|
|
||||||
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{}) {
|
|
||||||
o.app.debug.Printf("OLM [TRACE]: "+message+"\n", args)
|
|
||||||
}
|
|
||||||
|
|
||||||
var matrixFilter = gomatrix.Filter{
|
var matrixFilter = gomatrix.Filter{
|
||||||
Room: gomatrix.RoomFilter{
|
Room: gomatrix.RoomFilter{
|
||||||
Timeline: gomatrix.FilterPart{
|
Timeline: gomatrix.FilterPart{
|
||||||
Types: []event.Type{
|
Types: []event.Type{
|
||||||
event.NewEventType("m.room.message"),
|
event.EventMessage,
|
||||||
event.NewEventType("m.room.member"),
|
event.EventEncrypted,
|
||||||
|
event.StateMember,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -102,8 +56,10 @@ var matrixFilter = gomatrix.Filter{
|
|||||||
"room_id",
|
"room_id",
|
||||||
"state_key",
|
"state_key",
|
||||||
"sender",
|
"sender",
|
||||||
"content.body",
|
"content",
|
||||||
"content.membership",
|
"timestamp",
|
||||||
|
// "content.body",
|
||||||
|
// "content.membership",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,52 +74,33 @@ func newMatrixDaemon(app *appContext) (d *MatrixDaemon, err error) {
|
|||||||
languages: map[id.RoomID]string{},
|
languages: map[id.RoomID]string{},
|
||||||
isEncrypted: map[id.RoomID]bool{},
|
isEncrypted: map[id.RoomID]bool{},
|
||||||
app: app,
|
app: app,
|
||||||
|
start: time.Now().UnixNano() / 1e6,
|
||||||
}
|
}
|
||||||
d.bot, err = gomatrix.NewClient(homeserver, d.userID, token)
|
d.bot, err = gomatrix.NewClient(homeserver, d.userID, token)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
resp, err := d.bot.CreateFilter(&matrixFilter)
|
// resp, err := d.bot.CreateFilter(&matrixFilter)
|
||||||
d.bot.Store.SaveFilterID(d.userID, resp.FilterID)
|
// if err != nil {
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// d.bot.Store.SaveFilterID(d.userID, resp.FilterID)
|
||||||
for _, user := range app.storage.matrix {
|
for _, user := range app.storage.matrix {
|
||||||
if user.Lang != "" {
|
if user.Lang != "" {
|
||||||
d.languages[id.RoomID(user.RoomID)] = user.Lang
|
d.languages[id.RoomID(user.RoomID)] = user.Lang
|
||||||
}
|
}
|
||||||
d.isEncrypted[id.RoomID(user.RoomID)] = user.Encrypted
|
d.isEncrypted[id.RoomID(user.RoomID)] = user.Encrypted
|
||||||
}
|
}
|
||||||
dbPath := app.config.Section("files").Key("matrix_sql").String()
|
err = InitMatrixCrypto(d)
|
||||||
// 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.
|
|
||||||
os.Remove(dbPath)
|
|
||||||
cryptoStore, err := crypto.NewGobStore(dbPath)
|
|
||||||
// d.db, err = sql.Open("sqlite3", dbPath)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
olmLog := &olmLogger{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
|
|
||||||
// }
|
|
||||||
d.olm = crypto.NewOlmMachine(d.bot, olmLog, cryptoStore, crypto.StateStore(d))
|
|
||||||
// d.olm.AllowUnverifiedDevices = true
|
|
||||||
err = d.olm.Load()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
d.cryptoStore = cryptoStore
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *MatrixDaemon) generateAccessToken(homeserver, username, password string) (string, error) {
|
func (d *MatrixDaemon) generateAccessToken(homeserver, username, password string) (string, error) {
|
||||||
req := &gomatrix.ReqLogin{
|
req := &gomatrix.ReqLogin{
|
||||||
Type: "m.login.password",
|
Type: gomatrix.AuthTypePassword,
|
||||||
Identifier: gomatrix.UserIdentifier{
|
Identifier: gomatrix.UserIdentifier{
|
||||||
|
Type: gomatrix.IdentifierTypeUser,
|
||||||
User: username,
|
User: username,
|
||||||
Type: "m.id.user",
|
|
||||||
},
|
},
|
||||||
Password: password,
|
Password: password,
|
||||||
DeviceID: id.DeviceID("jfa-go-" + commit),
|
DeviceID: id.DeviceID("jfa-go-" + commit),
|
||||||
@ -180,36 +117,20 @@ func (d *MatrixDaemon) generateAccessToken(homeserver, username, password string
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *MatrixDaemon) run() {
|
func (d *MatrixDaemon) run() {
|
||||||
d.start = time.Now().UnixNano() / 1000000
|
startTime := d.start
|
||||||
d.app.info.Println("Starting Matrix bot daemon")
|
d.app.info.Println("Starting Matrix bot daemon")
|
||||||
syncer := d.bot.Syncer.(*gomatrix.DefaultSyncer)
|
syncer := d.bot.Syncer.(*gomatrix.DefaultSyncer)
|
||||||
|
HandleSyncerCrypto(startTime, d, syncer)
|
||||||
syncer.OnEventType(event.EventMessage, d.handleMessage)
|
syncer.OnEventType(event.EventMessage, d.handleMessage)
|
||||||
syncer.OnEventType(event.EventEncrypted, func(source gomatrix.EventSource, evt *event.Event) {
|
|
||||||
if evt.Timestamp < d.start {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
decrypted, err := d.olm.DecryptMegolmEvent(evt)
|
|
||||||
if err != nil {
|
|
||||||
d.app.err.Printf("Failed to decrypt Matrix message: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
d.handleMessage(source, decrypted)
|
|
||||||
})
|
|
||||||
syncer.OnSync(d.olm.ProcessSyncResponse)
|
|
||||||
syncer.OnEventType(event.StateMember, func(source gomatrix.EventSource, evt *event.Event) {
|
|
||||||
d.olm.HandleMemberEvent(evt)
|
|
||||||
})
|
|
||||||
|
|
||||||
// syncer.OnEventType("m.room.member", d.handleMembership)
|
|
||||||
if err := d.bot.Sync(); err != nil {
|
if err := d.bot.Sync(); err != nil {
|
||||||
d.app.err.Printf("Matrix sync failed: %v", err)
|
d.app.err.Printf("Matrix sync failed: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *MatrixDaemon) Shutdown() {
|
func (d *MatrixDaemon) Shutdown() {
|
||||||
d.olm.FlushStore()
|
CryptoShutdown(d)
|
||||||
d.bot.StopSync()
|
d.bot.StopSync()
|
||||||
d.db.Close()
|
|
||||||
d.Stopped = true
|
d.Stopped = true
|
||||||
close(d.ShutdownChannel)
|
close(d.ShutdownChannel)
|
||||||
}
|
}
|
||||||
@ -221,6 +142,7 @@ func (d *MatrixDaemon) handleMessage(source gomatrix.EventSource, evt *event.Eve
|
|||||||
if evt.Sender == d.userID {
|
if evt.Sender == d.userID {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
fmt.Printf("RECV %+v\n", evt.Content)
|
||||||
lang := "en-us"
|
lang := "en-us"
|
||||||
if l, ok := d.languages[evt.RoomID]; ok {
|
if l, ok := d.languages[evt.RoomID]; ok {
|
||||||
if _, ok := d.app.storage.lang.Telegram[l]; ok {
|
if _, ok := d.app.storage.lang.Telegram[l]; ok {
|
||||||
@ -272,20 +194,12 @@ func (d *MatrixDaemon) CreateRoom(userID string) (roomID id.RoomID, encrypted bo
|
|||||||
Visibility: "private",
|
Visibility: "private",
|
||||||
Invite: []id.UserID{id.UserID(userID)},
|
Invite: []id.UserID{id.UserID(userID)},
|
||||||
Topic: d.app.config.Section("matrix").Key("topic").String(),
|
Topic: d.app.config.Section("matrix").Key("topic").String(),
|
||||||
|
IsDirect: true,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_, err = d.bot.SendStateEvent(room.RoomID, event.StateEncryption, "", &event.EncryptionEventContent{
|
encrypted = EncryptRoom(d, room, id.UserID(userID))
|
||||||
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)
|
|
||||||
}
|
|
||||||
roomID = room.RoomID
|
roomID = room.RoomID
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -307,11 +221,13 @@ func (d *MatrixDaemon) SendStart(userID string) (ok bool) {
|
|||||||
Encrypted: encrypted,
|
Encrypted: encrypted,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
d.isEncrypted[roomID] = encrypted
|
err = d.send(
|
||||||
_, err = d.bot.SendText(
|
&event.MessageEventContent{
|
||||||
roomID,
|
MsgType: event.MsgText,
|
||||||
d.app.storage.lang.Telegram[lang].Strings.get("matrixStartMessage")+"\n\n"+pin+"\n\n"+
|
Body: d.app.storage.lang.Telegram[lang].Strings.get("matrixStartMessage") + "\n\n" + pin + "\n\n" +
|
||||||
d.app.storage.lang.Telegram[lang].Strings.template("languageMessage", tmpl{"command": "!lang"}),
|
d.app.storage.lang.Telegram[lang].Strings.template("languageMessage", tmpl{"command": "!lang"}),
|
||||||
|
},
|
||||||
|
roomID,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
d.app.err.Printf("Matrix: Failed to send welcome message to \"%s\": %v", userID, err)
|
d.app.err.Printf("Matrix: Failed to send welcome message to \"%s\": %v", userID, err)
|
||||||
@ -321,13 +237,25 @@ func (d *MatrixDaemon) SendStart(userID string) (ok bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *MatrixDaemon) send(content *event.MessageEventContent, roomID id.RoomID) (err error) {
|
||||||
|
if encrypted, ok := d.isEncrypted[roomID]; ok && encrypted {
|
||||||
|
err = SendEncrypted(d, content, roomID)
|
||||||
|
} else {
|
||||||
|
_, err = d.bot.SendMessageEvent(roomID, event.NewEventType("m.room.message"), content, gomatrix.ReqSendEvent{})
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (d *MatrixDaemon) Send(message *Message, users ...MatrixUser) (err error) {
|
func (d *MatrixDaemon) Send(message *Message, users ...MatrixUser) (err error) {
|
||||||
md := ""
|
md := ""
|
||||||
if message.Markdown != "" {
|
if message.Markdown != "" {
|
||||||
// Convert images to links
|
// Convert images to links
|
||||||
md = string(markdown.ToHTML([]byte(strings.ReplaceAll(message.Markdown, "![", "[")), nil, renderer))
|
md = string(markdown.ToHTML([]byte(strings.ReplaceAll(message.Markdown, "![", "[")), nil, renderer))
|
||||||
}
|
}
|
||||||
content := event.MessageEventContent{
|
content := &event.MessageEventContent{
|
||||||
MsgType: "m.text",
|
MsgType: "m.text",
|
||||||
Body: message.Text,
|
Body: message.Text,
|
||||||
}
|
}
|
||||||
@ -337,9 +265,9 @@ func (d *MatrixDaemon) Send(message *Message, users ...MatrixUser) (err error) {
|
|||||||
}
|
}
|
||||||
for _, user := range users {
|
for _, user := range users {
|
||||||
if user.Encrypted {
|
if user.Encrypted {
|
||||||
err = d.SendEncrypted(&content, user)
|
err = SendEncrypted(d, content, id.RoomID(user.RoomID))
|
||||||
} else {
|
} else {
|
||||||
_, err = d.bot.SendMessageEvent(id.RoomID(user.RoomID), event.NewEventType("m.room.message"), content, gomatrix.ReqSendEvent{})
|
err = d.send(content, id.RoomID(user.RoomID))
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
@ -348,28 +276,6 @@ func (d *MatrixDaemon) Send(message *Message, users ...MatrixUser) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *MatrixDaemon) SendEncrypted(content *event.MessageEventContent, users ...MatrixUser) (err error) {
|
|
||||||
for _, user := range users {
|
|
||||||
var encrypted *event.EncryptedEventContent
|
|
||||||
encrypted, err = d.olm.EncryptMegolmEvent(id.RoomID(user.RoomID), event.EventMessage, content)
|
|
||||||
if err == crypto.SessionExpired || err == crypto.SessionNotShared || err == crypto.NoGroupSession {
|
|
||||||
err = d.olm.ShareGroupSession(id.RoomID(user.RoomID), []id.UserID{id.UserID(user.UserID), d.userID})
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
encrypted, err = d.olm.EncryptMegolmEvent(id.RoomID(user.RoomID), event.EventMessage, content)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
_, err = d.bot.SendMessageEvent(id.RoomID(user.RoomID), event.EventEncrypted, &event.Content{Parsed: encrypted})
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// User enters ID on sign-up, a PIN is sent to them. They enter it on sign-up.
|
// User enters ID on sign-up, a PIN is sent to them. They enter it on sign-up.
|
||||||
|
|
||||||
// Message the user first, to avoid E2EE by default
|
// Message the user first, to avoid E2EE by default
|
||||||
|
217
matrix_crypto.go
Normal file
217
matrix_crypto.go
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"maunium.net/go/mautrix"
|
||||||
|
gomatrix "maunium.net/go/mautrix"
|
||||||
|
"maunium.net/go/mautrix/crypto"
|
||||||
|
"maunium.net/go/mautrix/event"
|
||||||
|
"maunium.net/go/mautrix/id"
|
||||||
|
)
|
||||||
|
|
||||||
|
type stateStore struct {
|
||||||
|
isEncrypted *map[id.RoomID]bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *stateStore) IsEncrypted(roomID id.RoomID) bool {
|
||||||
|
// encrypted, ok := (*m.isEncrypted)[roomID]
|
||||||
|
// fmt.Println("ISENCRYPTED", roomID, ok && encrypted)
|
||||||
|
// 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.
|
||||||
|
// os.Remove(dbPath)
|
||||||
|
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
|
||||||
|
// }
|
||||||
|
d.olm = crypto.NewOlmMachine(d.bot, olmLog, cryptoStore, &stateStore{&d.isEncrypted})
|
||||||
|
d.olm.AllowUnverifiedDevices = true
|
||||||
|
err = d.olm.Load()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
d.cryptoStore = cryptoStore
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func HandleSyncerCrypto(startTime int64, d *MatrixDaemon, syncer *mautrix.DefaultSyncer) {
|
||||||
|
if !d.Encryption {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
syncer.OnSync(func(resp *gomatrix.RespSync, since string) bool {
|
||||||
|
d.olm.ProcessSyncResponse(resp, since)
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
syncer.OnEventType(event.StateMember, func(source gomatrix.EventSource, evt *event.Event) {
|
||||||
|
d.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.olm.ShareGroupSession(evt.RoomID, userIDs)
|
||||||
|
// if err != nil {
|
||||||
|
// fmt.Println("FS", err)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
})
|
||||||
|
syncer.OnEventType(event.EventEncrypted, func(source gomatrix.EventSource, evt *event.Event) {
|
||||||
|
if evt.Timestamp < startTime {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Printf("%+v\n", d.cryptoStore.GroupSessions)
|
||||||
|
decrypted, err := d.olm.DecryptMegolmEvent(evt)
|
||||||
|
if err != nil {
|
||||||
|
d.app.err.Printf("Failed to decrypt Matrix message: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Println("RECV", decrypted.Content.Raw["body"])
|
||||||
|
d.handleMessage(source, decrypted)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func CryptoShutdown(d *MatrixDaemon) {
|
||||||
|
if d.Encryption {
|
||||||
|
d.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)
|
||||||
|
err = d.olm.ShareGroupSession(room.RoomID, userIDs)
|
||||||
|
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.olm.EncryptMegolmEvent(roomID, event.EventMessage, content)
|
||||||
|
if err == crypto.SessionExpired || err == crypto.SessionNotShared || err == crypto.NoGroupSession {
|
||||||
|
fmt.Println("SGS")
|
||||||
|
// err = d.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
|
||||||
|
}
|
||||||
|
fmt.Println("SHARETO", userIDs)
|
||||||
|
err = d.olm.ShareGroupSession(roomID, userIDs)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
encrypted, err = d.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
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user