mirror of
https://github.com/hrfee/jfa-go.git
synced 2024-12-22 09:00:10 +00:00
matrix: working E2EE, on by default
mautrix-go now include a cryptohelper package, which solves all my issues and just works. the setting is now on by default, however packages are not yet built with it.
This commit is contained in:
parent
86c7551ff8
commit
69569e556a
@ -614,20 +614,18 @@ func (app *appContext) MatrixConnect(gc *gin.Context) {
|
|||||||
if app.storage.GetMatrix() == nil {
|
if app.storage.GetMatrix() == nil {
|
||||||
app.storage.deprecatedMatrix = matrixStore{}
|
app.storage.deprecatedMatrix = matrixStore{}
|
||||||
}
|
}
|
||||||
roomID, encrypted, err := app.matrix.CreateRoom(req.UserID)
|
roomID, err := app.matrix.CreateRoom(req.UserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
app.err.Printf(lm.FailedCreateRoom, err)
|
app.err.Printf(lm.FailedCreateRoom, err)
|
||||||
respondBool(500, false, gc)
|
respondBool(500, false, gc)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
app.storage.SetMatrixKey(req.JellyfinID, MatrixUser{
|
app.storage.SetMatrixKey(req.JellyfinID, MatrixUser{
|
||||||
UserID: req.UserID,
|
UserID: req.UserID,
|
||||||
RoomID: string(roomID),
|
RoomID: string(roomID),
|
||||||
Lang: "en-us",
|
Lang: "en-us",
|
||||||
Contact: true,
|
Contact: true,
|
||||||
Encrypted: encrypted,
|
|
||||||
})
|
})
|
||||||
app.matrix.isEncrypted[roomID] = encrypted
|
|
||||||
respondBool(200, true, gc)
|
respondBool(200, true, gc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
4
auth.go
4
auth.go
@ -43,7 +43,7 @@ func (app *appContext) webAuth() gin.HandlerFunc {
|
|||||||
return app.authenticate
|
return app.authenticate
|
||||||
}
|
}
|
||||||
|
|
||||||
func (app *appContext) authLog(v any) { app.debug.Printf(lm.FailedAuthRequest, v) }
|
func (app *appContext) authLog(v any) { app.debug.PrintfCustomLevel(4, lm.FailedAuthRequest, v) }
|
||||||
|
|
||||||
// CreateToken returns a web token as well as a refresh token, which can be used to obtain new tokens.
|
// CreateToken returns a web token as well as a refresh token, which can be used to obtain new tokens.
|
||||||
func CreateToken(userId, jfId string, admin bool) (string, string, error) {
|
func CreateToken(userId, jfId string, admin bool) (string, string, error) {
|
||||||
@ -270,7 +270,7 @@ func (app *appContext) decodeValidateRefreshCookie(gc *gin.Context, cookieName s
|
|||||||
}
|
}
|
||||||
token, err := jwt.Parse(cookie, checkToken)
|
token, err := jwt.Parse(cookie, checkToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
app.authLog(lm.FailedParseJWT)
|
app.authLog(fmt.Sprintf(lm.FailedParseJWT, err))
|
||||||
respond(400, lm.InvalidJWT, gc)
|
respond(400, lm.InvalidJWT, gc)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -170,5 +170,6 @@ func newBackupDaemon(app *appContext) *GenericDaemon {
|
|||||||
app.makeBackup()
|
app.makeBackup()
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
d.Name("Backup")
|
||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
|
@ -1297,14 +1297,14 @@
|
|||||||
"description": "Default Matrix message language. Visit weblate if you'd like to translate."
|
"description": "Default Matrix message language. Visit weblate if you'd like to translate."
|
||||||
},
|
},
|
||||||
"encryption": {
|
"encryption": {
|
||||||
"name": "End-to-end encryption (experimental)",
|
"name": "End-to-end encryption",
|
||||||
"required": false,
|
"required": false,
|
||||||
"requires_restart": true,
|
"requires_restart": true,
|
||||||
"depends_true": "enabled",
|
"depends_true": "enabled",
|
||||||
"advanced": true,
|
"advanced": false,
|
||||||
"type": "bool",
|
"type": "bool",
|
||||||
"value": false,
|
"value": true,
|
||||||
"description": "Enable end-to-end encryption for messages. Very experimental, currently does not support receiving commands (e.g !lang)."
|
"description": "Enable end-to-end encryption for messages."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
1
go.mod
1
go.mod
@ -45,6 +45,7 @@ require (
|
|||||||
github.com/itchyny/timefmt-go v0.1.6
|
github.com/itchyny/timefmt-go v0.1.6
|
||||||
github.com/lithammer/shortuuid/v3 v3.0.7
|
github.com/lithammer/shortuuid/v3 v3.0.7
|
||||||
github.com/mailgun/mailgun-go/v4 v4.14.0
|
github.com/mailgun/mailgun-go/v4 v4.14.0
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.22
|
||||||
github.com/robert-nix/ansihtml v1.0.1
|
github.com/robert-nix/ansihtml v1.0.1
|
||||||
github.com/steambap/captcha v1.4.1
|
github.com/steambap/captcha v1.4.1
|
||||||
github.com/swaggo/files v1.0.1
|
github.com/swaggo/files v1.0.1
|
||||||
|
@ -131,12 +131,12 @@ func newHousekeepingDaemon(interval time.Duration, app *appContext) *GenericDaem
|
|||||||
func(app *appContext) { app.clearActivities() },
|
func(app *appContext) { app.clearActivities() },
|
||||||
)
|
)
|
||||||
|
|
||||||
d.Name("Housekeeping daemon")
|
d.Name("Housekeeping")
|
||||||
|
|
||||||
clearEmail := app.config.Section("email").Key("require_unique").MustBool(false)
|
clearEmail := app.config.Section("email").Key("require_unique").MustBool(false)
|
||||||
clearDiscord := app.config.Section("discord").Key("require_unique").MustBool(false) || app.config.Section("discord").Key("disable_enable_role").MustBool(false)
|
clearDiscord := discordEnabled && (app.config.Section("discord").Key("require_unique").MustBool(false) || app.config.Section("discord").Key("disable_enable_role").MustBool(false))
|
||||||
clearTelegram := app.config.Section("telegram").Key("require_unique").MustBool(false)
|
clearTelegram := telegramEnabled && (app.config.Section("telegram").Key("require_unique").MustBool(false))
|
||||||
clearMatrix := app.config.Section("matrix").Key("require_unique").MustBool(false)
|
clearMatrix := matrixEnabled && (app.config.Section("matrix").Key("require_unique").MustBool(false))
|
||||||
clearPWR := app.config.Section("captcha").Key("enabled").MustBool(false) && !app.config.Section("captcha").Key("recaptcha").MustBool(false)
|
clearPWR := app.config.Section("captcha").Key("enabled").MustBool(false) && !app.config.Section("captcha").Key("recaptcha").MustBool(false)
|
||||||
|
|
||||||
if clearEmail || clearDiscord || clearTelegram || clearMatrix {
|
if clearEmail || clearDiscord || clearTelegram || clearMatrix {
|
||||||
|
@ -77,6 +77,6 @@ func newJellyseerrDaemon(interval time.Duration, app *appContext) *GenericDaemon
|
|||||||
app.SynchronizeJellyseerrUsers()
|
app.SynchronizeJellyseerrUsers()
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
d.Name("Jellyseerr import daemon")
|
d.Name("Jellyseerr import")
|
||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
|
@ -84,6 +84,18 @@ func (l *Logger) Printf(format string, v ...interface{}) {
|
|||||||
l.logger.Print(out)
|
l.logger.Print(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l *Logger) PrintfCustomLevel(level int, format string, v ...interface{}) {
|
||||||
|
if l.empty {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var out string
|
||||||
|
if l.shortfile {
|
||||||
|
out = Lshortfile(level)
|
||||||
|
}
|
||||||
|
out += " " + l.printer.Sprintf(format, v...)
|
||||||
|
l.logger.Print(out)
|
||||||
|
}
|
||||||
|
|
||||||
func (l *Logger) Print(v ...interface{}) {
|
func (l *Logger) Print(v ...interface{}) {
|
||||||
if l.empty {
|
if l.empty {
|
||||||
return
|
return
|
||||||
|
96
matrix.go
96
matrix.go
@ -2,9 +2,11 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gomarkdown/markdown"
|
"github.com/gomarkdown/markdown"
|
||||||
@ -15,18 +17,23 @@ import (
|
|||||||
"maunium.net/go/mautrix/id"
|
"maunium.net/go/mautrix/id"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
DEVICE_ID = id.DeviceID("jfa-go")
|
||||||
|
)
|
||||||
|
|
||||||
type MatrixDaemon struct {
|
type MatrixDaemon struct {
|
||||||
Stopped bool
|
Stopped bool
|
||||||
ShutdownChannel chan string
|
bot *mautrix.Client
|
||||||
bot *mautrix.Client
|
userID id.UserID
|
||||||
userID id.UserID
|
homeserver string
|
||||||
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
|
Encryption bool
|
||||||
isEncrypted map[id.RoomID]bool
|
crypto *Crypto
|
||||||
crypto Crypto
|
app *appContext
|
||||||
app *appContext
|
start int64
|
||||||
start int64
|
cancellation sync.WaitGroup
|
||||||
|
cancel context.CancelFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
type UnverifiedUser struct {
|
type UnverifiedUser struct {
|
||||||
@ -57,23 +64,33 @@ var matrixFilter = mautrix.Filter{
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *MatrixDaemon) renderUserID(uid id.UserID) id.UserID {
|
||||||
|
if uid[0] != '@' {
|
||||||
|
uid = "@" + uid
|
||||||
|
}
|
||||||
|
if !strings.ContainsRune(string(uid), ':') {
|
||||||
|
uid = id.UserID(string(uid) + ":" + d.homeserver)
|
||||||
|
}
|
||||||
|
return uid
|
||||||
|
}
|
||||||
|
|
||||||
func newMatrixDaemon(app *appContext) (d *MatrixDaemon, err error) {
|
func newMatrixDaemon(app *appContext) (d *MatrixDaemon, err error) {
|
||||||
matrix := app.config.Section("matrix")
|
matrix := app.config.Section("matrix")
|
||||||
homeserver := matrix.Key("homeserver").String()
|
|
||||||
token := matrix.Key("token").String()
|
token := matrix.Key("token").String()
|
||||||
d = &MatrixDaemon{
|
d = &MatrixDaemon{
|
||||||
ShutdownChannel: make(chan string),
|
userID: id.UserID(matrix.Key("user_id").String()),
|
||||||
userID: id.UserID(matrix.Key("user_id").String()),
|
homeserver: matrix.Key("homeserver").String(),
|
||||||
tokens: map[string]UnverifiedUser{},
|
tokens: map[string]UnverifiedUser{},
|
||||||
languages: map[id.RoomID]string{},
|
languages: map[id.RoomID]string{},
|
||||||
isEncrypted: map[id.RoomID]bool{},
|
app: app,
|
||||||
app: app,
|
start: time.Now().UnixNano() / 1e6,
|
||||||
start: time.Now().UnixNano() / 1e6,
|
|
||||||
}
|
}
|
||||||
d.bot, err = mautrix.NewClient(homeserver, d.userID, token)
|
d.userID = d.renderUserID(d.userID)
|
||||||
|
d.bot, err = mautrix.NewClient(d.homeserver, d.userID, token)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
d.bot.DeviceID = DEVICE_ID
|
||||||
// resp, err := d.bot.CreateFilter(&matrixFilter)
|
// resp, err := d.bot.CreateFilter(&matrixFilter)
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// return
|
// return
|
||||||
@ -83,7 +100,6 @@ func newMatrixDaemon(app *appContext) (d *MatrixDaemon, err error) {
|
|||||||
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
|
|
||||||
}
|
}
|
||||||
err = InitMatrixCrypto(d)
|
err = InitMatrixCrypto(d)
|
||||||
return
|
return
|
||||||
@ -102,7 +118,7 @@ func (d *MatrixDaemon) generateAccessToken(homeserver, username, password string
|
|||||||
User: username,
|
User: username,
|
||||||
},
|
},
|
||||||
Password: password,
|
Password: password,
|
||||||
DeviceID: id.DeviceID("jfa-go-" + commit),
|
DeviceID: DEVICE_ID,
|
||||||
}
|
}
|
||||||
bot, err := mautrix.NewClient(homeserver, id.UserID(username), "")
|
bot, err := mautrix.NewClient(homeserver, id.UserID(username), "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -116,22 +132,25 @@ func (d *MatrixDaemon) generateAccessToken(homeserver, username, password string
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *MatrixDaemon) run() {
|
func (d *MatrixDaemon) run() {
|
||||||
startTime := d.start
|
|
||||||
d.app.info.Println(lm.StartDaemon, lm.Matrix)
|
|
||||||
syncer := d.bot.Syncer.(*mautrix.DefaultSyncer)
|
syncer := d.bot.Syncer.(*mautrix.DefaultSyncer)
|
||||||
HandleSyncerCrypto(startTime, d, syncer)
|
|
||||||
syncer.OnEventType(event.EventMessage, d.handleMessage)
|
syncer.OnEventType(event.EventMessage, d.handleMessage)
|
||||||
|
|
||||||
if err := d.bot.Sync(); err != nil {
|
d.app.info.Printf(lm.StartDaemon, lm.Matrix)
|
||||||
|
|
||||||
|
var syncCtx context.Context
|
||||||
|
syncCtx, d.cancel = context.WithCancel(context.Background())
|
||||||
|
d.cancellation.Add(1)
|
||||||
|
|
||||||
|
if err := d.bot.SyncWithContext(syncCtx); err != nil && !errors.Is(err, context.Canceled) {
|
||||||
d.app.err.Printf(lm.FailedSyncMatrix, err)
|
d.app.err.Printf(lm.FailedSyncMatrix, err)
|
||||||
}
|
}
|
||||||
|
d.cancellation.Done()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *MatrixDaemon) Shutdown() {
|
func (d *MatrixDaemon) Shutdown() {
|
||||||
CryptoShutdown(d)
|
d.cancel()
|
||||||
d.bot.StopSync()
|
d.cancellation.Wait()
|
||||||
d.Stopped = true
|
d.Stopped = true
|
||||||
close(d.ShutdownChannel)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *MatrixDaemon) handleMessage(ctx context.Context, evt *event.Event) {
|
func (d *MatrixDaemon) handleMessage(ctx context.Context, evt *event.Event) {
|
||||||
@ -184,7 +203,7 @@ func (d *MatrixDaemon) commandLang(evt *event.Event, code, lang string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *MatrixDaemon) CreateRoom(userID string) (roomID id.RoomID, encrypted bool, err error) {
|
func (d *MatrixDaemon) CreateRoom(userID string) (roomID id.RoomID, err error) {
|
||||||
var room *mautrix.RespCreateRoom
|
var room *mautrix.RespCreateRoom
|
||||||
room, err = d.bot.CreateRoom(context.TODO(), &mautrix.ReqCreateRoom{
|
room, err = d.bot.CreateRoom(context.TODO(), &mautrix.ReqCreateRoom{
|
||||||
Visibility: "private",
|
Visibility: "private",
|
||||||
@ -195,13 +214,14 @@ func (d *MatrixDaemon) CreateRoom(userID string) (roomID id.RoomID, encrypted bo
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
encrypted = EncryptRoom(d, room, id.UserID(userID))
|
// encrypted = EncryptRoom(d, room, id.UserID(userID))
|
||||||
roomID = room.RoomID
|
roomID = room.RoomID
|
||||||
|
err = EncryptRoom(d, roomID)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *MatrixDaemon) SendStart(userID string) (ok bool) {
|
func (d *MatrixDaemon) SendStart(userID string) (ok bool) {
|
||||||
roomID, encrypted, err := d.CreateRoom(userID)
|
roomID, err := d.CreateRoom(userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
d.app.err.Printf(lm.FailedCreateMatrixRoom, userID, err)
|
d.app.err.Printf(lm.FailedCreateMatrixRoom, userID, err)
|
||||||
return
|
return
|
||||||
@ -211,10 +231,9 @@ func (d *MatrixDaemon) SendStart(userID string) (ok bool) {
|
|||||||
d.tokens[pin] = UnverifiedUser{
|
d.tokens[pin] = UnverifiedUser{
|
||||||
false,
|
false,
|
||||||
&MatrixUser{
|
&MatrixUser{
|
||||||
RoomID: string(roomID),
|
RoomID: string(roomID),
|
||||||
UserID: userID,
|
UserID: userID,
|
||||||
Lang: lang,
|
Lang: lang,
|
||||||
Encrypted: encrypted,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
err = d.sendToRoom(
|
err = d.sendToRoom(
|
||||||
@ -234,12 +253,13 @@ func (d *MatrixDaemon) SendStart(userID string) (ok bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *MatrixDaemon) sendToRoom(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 {
|
return d.send(content, roomID)
|
||||||
|
/*if encrypted, ok := d.isEncrypted[roomID]; ok && encrypted {
|
||||||
err = SendEncrypted(d, content, roomID)
|
err = SendEncrypted(d, content, roomID)
|
||||||
} else {
|
} else {
|
||||||
_, err = d.bot.SendMessageEvent(context.TODO(), roomID, event.EventMessage, content, mautrix.ReqSendEvent{})
|
_, err = d.bot.SendMessageEvent(context.TODO(), roomID, event.EventMessage, content, mautrix.ReqSendEvent{})
|
||||||
}
|
}
|
||||||
return
|
return*/
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *MatrixDaemon) send(content *event.MessageEventContent, roomID id.RoomID) (err error) {
|
func (d *MatrixDaemon) send(content *event.MessageEventContent, roomID id.RoomID) (err error) {
|
||||||
|
218
matrix_crypto.go
218
matrix_crypto.go
@ -4,224 +4,54 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"context"
|
||||||
"strings"
|
|
||||||
|
|
||||||
lm "github.com/hrfee/jfa-go/logmessages"
|
_ "github.com/mattn/go-sqlite3"
|
||||||
"maunium.net/go/mautrix"
|
"maunium.net/go/mautrix/crypto/cryptohelper"
|
||||||
"maunium.net/go/mautrix/crypto"
|
|
||||||
"maunium.net/go/mautrix/event"
|
"maunium.net/go/mautrix/event"
|
||||||
"maunium.net/go/mautrix/id"
|
"maunium.net/go/mautrix/id"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Crypto struct {
|
type Crypto struct {
|
||||||
cryptoStore *crypto.GobStore
|
helper *cryptohelper.CryptoHelper
|
||||||
olm *crypto.OlmMachine
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func MatrixE2EE() bool { return true }
|
func MatrixE2EE() bool { return true }
|
||||||
|
|
||||||
type stateStore struct {
|
func InitMatrixCrypto(d *MatrixDaemon) error {
|
||||||
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(lm.MatrixOlmLog, fmt.Sprintf(message, args))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o olmLogger) Warn(message string, args ...interface{}) {
|
|
||||||
o.app.info.Printf(lm.MatrixOlmLog, fmt.Sprintf(message, args))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o olmLogger) Debug(message string, args ...interface{}) {
|
|
||||||
o.app.debug.Printf(lm.MatrixOlmLog, fmt.Sprintf(message, args))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o olmLogger) Trace(message string, args ...interface{}) {
|
|
||||||
if strings.HasPrefix(message, "Got membership state event") {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
o.app.debug.Printf(lm.MatrixOlmTracelog, fmt.Sprintf(message, args))
|
|
||||||
}
|
|
||||||
|
|
||||||
func InitMatrixCrypto(d *MatrixDaemon) (err error) {
|
|
||||||
d.Encryption = d.app.config.Section("matrix").Key("encryption").MustBool(false)
|
d.Encryption = d.app.config.Section("matrix").Key("encryption").MustBool(false)
|
||||||
if !d.Encryption {
|
if !d.Encryption {
|
||||||
return
|
// return fmt.Errorf("encryption disabled")
|
||||||
}
|
return nil
|
||||||
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()
|
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.
|
var err error
|
||||||
// This obviously isn't right, but it seems to work.
|
d.crypto = &Crypto{}
|
||||||
// Since its not really used anyway, just use the deprecated GobStore. This reduces cgo usage anyway.
|
d.crypto.helper, err = cryptohelper.NewCryptoHelper(d.bot, []byte("jfa-go"), dbPath)
|
||||||
var cryptoStore *crypto.GobStore
|
|
||||||
cryptoStore, err = crypto.NewGobStore(dbPath)
|
|
||||||
// d.db, err = sql.Open("sqlite3", dbPath)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
olmLog := &olmLogger{d.app}
|
|
||||||
// deviceID := "jfa-go" + commit
|
err = d.crypto.helper.Init(context.TODO())
|
||||||
// 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 {
|
if err != nil {
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
d.crypto = Crypto{
|
|
||||||
cryptoStore: cryptoStore,
|
d.bot.Crypto = d.crypto.helper
|
||||||
olm: olm,
|
|
||||||
}
|
d.Encryption = true
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func HandleSyncerCrypto(startTime int64, d *MatrixDaemon, syncer *mautrix.DefaultSyncer) {
|
func EncryptRoom(d *MatrixDaemon, roomID id.RoomID) error {
|
||||||
if !d.Encryption {
|
if !d.Encryption {
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
syncer.OnSync(func(resp *mautrix.RespSync, since string) bool {
|
_, err := d.bot.SendStateEvent(context.TODO(), roomID, event.StateEncryption, "", event.EncryptionEventContent{
|
||||||
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(lm.FailedDecryptMatrixMessage, 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,
|
Algorithm: id.AlgorithmMegolmV1,
|
||||||
RotationPeriodMillis: 7 * 24 * 60 * 60 * 1000,
|
RotationPeriodMillis: 7 * 24 * 60 * 60 * 1000,
|
||||||
RotationPeriodMessages: 100,
|
RotationPeriodMessages: 100,
|
||||||
})
|
})
|
||||||
if err == nil {
|
return err
|
||||||
encrypted = true
|
|
||||||
} else {
|
|
||||||
d.app.debug.Printf(lm.FailedEnableMatrixEncryption, room.RoomID, 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
|
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,9 @@
|
|||||||
|
//go:build !e2ee
|
||||||
// +build !e2ee
|
// +build !e2ee
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import "maunium.net/go/mautrix/id"
|
||||||
"maunium.net/go/mautrix"
|
|
||||||
"maunium.net/go/mautrix/event"
|
|
||||||
"maunium.net/go/mautrix/id"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Crypto struct{}
|
type Crypto struct{}
|
||||||
|
|
||||||
@ -17,19 +14,4 @@ func InitMatrixCrypto(d *MatrixDaemon) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func HandleSyncerCrypto(startTime int64, d *MatrixDaemon, syncer *mautrix.DefaultSyncer) {
|
func EncryptRoom(d *MatrixDaemon, roomID id.RoomID) error { return nil }
|
||||||
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
|
|
||||||
}
|
|
||||||
|
@ -40,7 +40,7 @@ func (app *appContext) GenResetLink(pin string) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (app *appContext) StartPWR() {
|
func (app *appContext) StartPWR() {
|
||||||
app.info.Println(lm.StartDaemon, "PWR")
|
app.info.Printf(lm.StartDaemon, "PWR")
|
||||||
path := app.config.Section("password_resets").Key("watch_directory").String()
|
path := app.config.Section("password_resets").Key("watch_directory").String()
|
||||||
if _, err := os.Stat(path); os.IsNotExist(err) {
|
if _, err := os.Stat(path); os.IsNotExist(err) {
|
||||||
app.err.Printf(lm.FailedStartDaemon, "PWR", fmt.Sprintf(lm.PathNotFound, path))
|
app.err.Printf(lm.FailedStartDaemon, "PWR", fmt.Sprintf(lm.PathNotFound, path))
|
||||||
|
@ -650,7 +650,6 @@ type TelegramUser struct {
|
|||||||
|
|
||||||
type MatrixUser struct {
|
type MatrixUser struct {
|
||||||
RoomID string
|
RoomID string
|
||||||
Encrypted bool
|
|
||||||
UserID string
|
UserID string
|
||||||
Lang string
|
Lang string
|
||||||
Contact bool
|
Contact bool
|
||||||
|
Loading…
Reference in New Issue
Block a user