diff --git a/Makefile b/Makefile index e159a60..8be3882 100644 --- a/Makefile +++ b/Makefile @@ -18,22 +18,30 @@ else ifneq ($(UPDATER), off) LDFLAGS := $(LDFLAGS) -X main.updater=$(UPDATER) endif + + INTERNAL ?= on +TRAY ?= off +E2EE ?= off +TAGS := -tags " + ifeq ($(INTERNAL), on) - TAGS := DATA := data else DATA := build/data - TAGS := -tags external + TAGS := $(TAGS) external endif -TRAY ?= off -ifeq ($(INTERNAL)$(TRAY), offon) +ifeq ($(TRAY), on) TAGS := $(TAGS) tray -else ifeq ($(INTERNAL)$(TRAY), onon) - TAGS := -tags tray endif +ifeq ($(E2EE), on) + TAGS := $(TAGS) e2ee +endif + +TAGS := $(TAGS)" + OS := $(shell go env GOOS) ifeq ($(TRAY)$(OS), onwindows) LDFLAGS := $(LDFLAGS) -H=windowsgui diff --git a/api.go b/api.go index f0afce1..fa41da0 100644 --- a/api.go +++ b/api.go @@ -1667,6 +1667,16 @@ func (app *appContext) GetConfig(gc *gin.Context) { } } } + if !MatrixE2EE() { + delete(resp.Sections["matrix"].Settings, "encryption") + for i, v := range resp.Sections["matrix"].Order { + if v == "encryption" { + sect := resp.Sections["matrix"] + sect.Order = append(sect.Order[:i], sect.Order[i+1:]...) + resp.Sections["matrix"] = sect + } + } + } for sectName, section := range resp.Sections { for settingName, setting := range section.Settings { val := app.config.Section(sectName).Key(settingName) diff --git a/config/config-base.json b/config/config-base.json index 3c4fb5b..9e573e7 100644 --- a/config/config-base.json +++ b/config/config-base.json @@ -747,6 +747,16 @@ ], "value": "en-us", "description": "Default Matrix message language. Visit weblate if you'd like to translate." + }, + "encryption": { + "name": "End-to-end encryption (experimental)", + "required": false, + "requires_restart": true, + "depends_true": "enabled", + "advanced": true, + "type": "bool", + "value": false, + "description": "Enable end-to-end encryption for messages. Very experimental, currently does not support receiving commands (e.g !lang)." } } }, diff --git a/matrix.go b/matrix.go index 613d74f..ccc4f72 100644 --- a/matrix.go +++ b/matrix.go @@ -6,7 +6,7 @@ import ( "time" "github.com/gomarkdown/markdown" - gomatrix "maunium.net/go/mautrix" + "maunium.net/go/mautrix" "maunium.net/go/mautrix/crypto" "maunium.net/go/mautrix/event" "maunium.net/go/mautrix/id" @@ -15,7 +15,7 @@ import ( type MatrixDaemon struct { Stopped bool ShutdownChannel chan string - bot *gomatrix.Client + bot *mautrix.Client userID id.UserID tokens map[string]UnverifiedUser // Map of tokens to users languages map[id.RoomID]string // Map of roomIDs to language codes @@ -40,9 +40,9 @@ type MatrixUser struct { Contact bool } -var matrixFilter = gomatrix.Filter{ - Room: gomatrix.RoomFilter{ - Timeline: gomatrix.FilterPart{ +var matrixFilter = mautrix.Filter{ + Room: mautrix.RoomFilter{ + Timeline: mautrix.FilterPart{ Types: []event.Type{ event.EventMessage, event.EventEncrypted, @@ -76,7 +76,7 @@ func newMatrixDaemon(app *appContext) (d *MatrixDaemon, err error) { app: app, start: time.Now().UnixNano() / 1e6, } - d.bot, err = gomatrix.NewClient(homeserver, d.userID, token) + d.bot, err = mautrix.NewClient(homeserver, d.userID, token) if err != nil { return } @@ -96,16 +96,16 @@ func newMatrixDaemon(app *appContext) (d *MatrixDaemon, err error) { } func (d *MatrixDaemon) generateAccessToken(homeserver, username, password string) (string, error) { - req := &gomatrix.ReqLogin{ - Type: gomatrix.AuthTypePassword, - Identifier: gomatrix.UserIdentifier{ - Type: gomatrix.IdentifierTypeUser, + req := &mautrix.ReqLogin{ + Type: mautrix.AuthTypePassword, + Identifier: mautrix.UserIdentifier{ + Type: mautrix.IdentifierTypeUser, User: username, }, Password: password, DeviceID: id.DeviceID("jfa-go-" + commit), } - bot, err := gomatrix.NewClient(homeserver, id.UserID(username), "") + bot, err := mautrix.NewClient(homeserver, id.UserID(username), "") if err != nil { return "", err } @@ -119,7 +119,7 @@ func (d *MatrixDaemon) generateAccessToken(homeserver, username, password string func (d *MatrixDaemon) run() { startTime := d.start d.app.info.Println("Starting Matrix bot daemon") - syncer := d.bot.Syncer.(*gomatrix.DefaultSyncer) + syncer := d.bot.Syncer.(*mautrix.DefaultSyncer) HandleSyncerCrypto(startTime, d, syncer) syncer.OnEventType(event.EventMessage, d.handleMessage) @@ -135,7 +135,7 @@ func (d *MatrixDaemon) Shutdown() { close(d.ShutdownChannel) } -func (d *MatrixDaemon) handleMessage(source gomatrix.EventSource, evt *event.Event) { +func (d *MatrixDaemon) handleMessage(source mautrix.EventSource, evt *event.Event) { if evt.Timestamp < d.start { return } @@ -189,8 +189,8 @@ func (d *MatrixDaemon) commandLang(evt *event.Event, code, lang string) { } func (d *MatrixDaemon) CreateRoom(userID string) (roomID id.RoomID, encrypted bool, err error) { - var room *gomatrix.RespCreateRoom - room, err = d.bot.CreateRoom(&gomatrix.ReqCreateRoom{ + var room *mautrix.RespCreateRoom + room, err = d.bot.CreateRoom(&mautrix.ReqCreateRoom{ Visibility: "private", Invite: []id.UserID{id.UserID(userID)}, Topic: d.app.config.Section("matrix").Key("topic").String(), @@ -221,7 +221,7 @@ func (d *MatrixDaemon) SendStart(userID string) (ok bool) { Encrypted: encrypted, }, } - err = d.send( + err = d.sendToRoom( &event.MessageEventContent{ MsgType: event.MsgText, Body: d.app.storage.lang.Telegram[lang].Strings.get("matrixStartMessage") + "\n\n" + pin + "\n\n" + @@ -237,18 +237,20 @@ func (d *MatrixDaemon) SendStart(userID string) (ok bool) { return } -func (d *MatrixDaemon) send(content *event.MessageEventContent, roomID id.RoomID) (err error) { +func (d *MatrixDaemon) sendToRoom(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 + _, err = d.bot.SendMessageEvent(roomID, event.EventMessage, content, mautrix.ReqSendEvent{}) } return } +func (d *MatrixDaemon) send(content *event.MessageEventContent, roomID id.RoomID) (err error) { + _, err = d.bot.SendMessageEvent(roomID, event.EventMessage, content, mautrix.ReqSendEvent{}) + return +} + func (d *MatrixDaemon) Send(message *Message, users ...MatrixUser) (err error) { md := "" if message.Markdown != "" { @@ -264,11 +266,7 @@ func (d *MatrixDaemon) Send(message *Message, users ...MatrixUser) (err error) { content.Format = "org.matrix.custom.html" } for _, user := range users { - if user.Encrypted { - err = SendEncrypted(d, content, id.RoomID(user.RoomID)) - } else { - err = d.send(content, id.RoomID(user.RoomID)) - } + err = d.sendToRoom(content, id.RoomID(user.RoomID)) if err != nil { return } diff --git a/matrix_crypto.go b/matrix_crypto.go index da8c618..a64e50f 100644 --- a/matrix_crypto.go +++ b/matrix_crypto.go @@ -1,3 +1,5 @@ +// +build e2ee + package main import ( @@ -5,19 +7,19 @@ import ( "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" ) +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] - // fmt.Println("ISENCRYPTED", roomID, ok && encrypted) // return ok && encrypted return true } @@ -117,11 +119,11 @@ func HandleSyncerCrypto(startTime int64, d *MatrixDaemon, syncer *mautrix.Defaul if !d.Encryption { return } - syncer.OnSync(func(resp *gomatrix.RespSync, since string) bool { + syncer.OnSync(func(resp *mautrix.RespSync, since string) bool { d.olm.ProcessSyncResponse(resp, since) return true }) - syncer.OnEventType(event.StateMember, func(source gomatrix.EventSource, evt *event.Event) { + syncer.OnEventType(event.StateMember, func(source mautrix.EventSource, evt *event.Event) { d.olm.HandleMemberEvent(evt) // if evt.Content.AsMember().Membership != event.MembershipJoin { // return @@ -137,7 +139,7 @@ func HandleSyncerCrypto(startTime int64, d *MatrixDaemon, syncer *mautrix.Defaul // return // } }) - syncer.OnEventType(event.EventEncrypted, func(source gomatrix.EventSource, evt *event.Event) { + syncer.OnEventType(event.EventEncrypted, func(source mautrix.EventSource, evt *event.Event) { if evt.Timestamp < startTime { return } @@ -147,7 +149,6 @@ func HandleSyncerCrypto(startTime int64, d *MatrixDaemon, syncer *mautrix.Defaul d.app.err.Printf("Failed to decrypt Matrix message: %v", err) return } - fmt.Println("RECV", decrypted.Content.Raw["body"]) d.handleMessage(source, decrypted) }) } @@ -192,14 +193,12 @@ func SendEncrypted(d *MatrixDaemon, content *event.MessageEventContent, roomID i 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 diff --git a/matrix_nocrypto.go b/matrix_nocrypto.go new file mode 100644 index 0000000..b49f720 --- /dev/null +++ b/matrix_nocrypto.go @@ -0,0 +1,33 @@ +// +build !e2ee + +package main + +import ( + "maunium.net/go/mautrix" + "maunium.net/go/mautrix/event" + "maunium.net/go/mautrix/id" +) + +func MatrixE2EE() bool { return false } + +func InitMatrixCrypto(d *MatrixDaemon) (err error) { + d.Encryption = false + return +} + +func HandleSyncerCrypto(startTime int64, d *MatrixDaemon, syncer *mautrix.DefaultSyncer) { + return +} + +func CryptoShutdown(d *MatrixDaemon) { + return +} + +func EncryptRoom(d *MatrixDaemon, room *mautrix.RespCreateRoom, userID id.UserID) (encrypted bool) { + return +} + +func SendEncrypted(d *MatrixDaemon, content *event.MessageEventContent, roomID id.RoomID) (err error) { + err = d.send(content, roomID) + return +}