Matrix E2EE-Entschlüsselung via mautrix-go (goolm) integrieren
This commit is contained in:
@@ -10,6 +10,10 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"maunium.net/go/mautrix"
|
||||
"maunium.net/go/mautrix/crypto/cryptohelper"
|
||||
"maunium.net/go/mautrix/event"
|
||||
)
|
||||
|
||||
type MatrixClient struct {
|
||||
@@ -18,6 +22,7 @@ type MatrixClient struct {
|
||||
RoomID string
|
||||
Limit int
|
||||
httpClient *http.Client
|
||||
crypto *cryptohelper.CryptoHelper
|
||||
}
|
||||
|
||||
func newMatrixClientFromEnv() *MatrixClient {
|
||||
@@ -36,15 +41,43 @@ func newMatrixClientFromEnv() *MatrixClient {
|
||||
limit = 100
|
||||
}
|
||||
|
||||
return &MatrixClient{
|
||||
m := &MatrixClient{
|
||||
HomeserverURL: hs,
|
||||
AccessToken: token,
|
||||
RoomID: roomID,
|
||||
Limit: limit,
|
||||
httpClient: &http.Client{
|
||||
Timeout: 6 * time.Second,
|
||||
Timeout: 8 * time.Second,
|
||||
},
|
||||
}
|
||||
|
||||
if readEnv("MATRIX_ENABLE_CRYPTO", "1") != "0" {
|
||||
m.crypto = initMatrixCrypto(hs, token)
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func initMatrixCrypto(hs, token string) *cryptohelper.CryptoHelper {
|
||||
cli, err := mautrix.NewClient(hs, "", token)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if whoami, err := cli.Whoami(context.Background()); err == nil && whoami != nil {
|
||||
cli.SetCredentials(whoami.UserID, token)
|
||||
}
|
||||
|
||||
storePath := readEnv("MATRIX_CRYPTO_STORE_PATH", "/tmp/farmcal-matrix-crypto.db")
|
||||
pickleKey := []byte(readEnv("MATRIX_PICKLE_KEY", token))
|
||||
|
||||
helper, err := cryptohelper.NewCryptoHelper(cli, pickleKey, storePath)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
if err = helper.Init(context.Background()); err != nil {
|
||||
return nil
|
||||
}
|
||||
return helper
|
||||
}
|
||||
|
||||
func (m *MatrixClient) FetchRecentMessages(ctx context.Context) ([]MatrixMessage, error) {
|
||||
@@ -67,19 +100,11 @@ func (m *MatrixClient) FetchRecentMessages(ctx context.Context) ([]MatrixMessage
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
||||
return nil, errors.New("matrix sync failed: " + strconv.Itoa(resp.StatusCode))
|
||||
return nil, errors.New("matrix messages failed: " + strconv.Itoa(resp.StatusCode))
|
||||
}
|
||||
|
||||
var messagesResp struct {
|
||||
Chunk []struct {
|
||||
Type string `json:"type"`
|
||||
Sender string `json:"sender"`
|
||||
OriginServerTS int64 `json:"origin_server_ts"`
|
||||
Content struct {
|
||||
MsgType string `json:"msgtype"`
|
||||
Body string `json:"body"`
|
||||
} `json:"content"`
|
||||
} `json:"chunk"`
|
||||
Chunk []json.RawMessage `json:"chunk"`
|
||||
}
|
||||
if err := json.NewDecoder(resp.Body).Decode(&messagesResp); err != nil {
|
||||
return nil, err
|
||||
@@ -90,30 +115,69 @@ func (m *MatrixClient) FetchRecentMessages(ctx context.Context) ([]MatrixMessage
|
||||
|
||||
out := make([]MatrixMessage, 0, len(messagesResp.Chunk))
|
||||
for i := len(messagesResp.Chunk) - 1; i >= 0; i-- {
|
||||
ev := messagesResp.Chunk[i]
|
||||
switch ev.Type {
|
||||
case "m.room.message":
|
||||
if ev.Content.MsgType != "m.text" && ev.Content.MsgType != "m.notice" {
|
||||
continue
|
||||
}
|
||||
body := strings.TrimSpace(ev.Content.Body)
|
||||
if body == "" {
|
||||
continue
|
||||
}
|
||||
ts := time.UnixMilli(ev.OriginServerTS).Local().Format("02.01.2006 15:04")
|
||||
out = append(out, MatrixMessage{
|
||||
Sender: ev.Sender,
|
||||
Body: body,
|
||||
Timestamp: ts,
|
||||
})
|
||||
case "m.room.encrypted":
|
||||
ts := time.UnixMilli(ev.OriginServerTS).Local().Format("02.01.2006 15:04")
|
||||
out = append(out, MatrixMessage{
|
||||
Sender: ev.Sender,
|
||||
Body: "[Verschlüsselte Nachricht]",
|
||||
Timestamp: ts,
|
||||
})
|
||||
ev := &event.Event{}
|
||||
if err := json.Unmarshal(messagesResp.Chunk[i], ev); err != nil {
|
||||
continue
|
||||
}
|
||||
msg, ok := m.mapEventToMessage(ctx, ev)
|
||||
if ok {
|
||||
out = append(out, msg)
|
||||
}
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (m *MatrixClient) mapEventToMessage(ctx context.Context, ev *event.Event) (MatrixMessage, bool) {
|
||||
ts := time.UnixMilli(ev.Timestamp).Local().Format("02.01.2006 15:04")
|
||||
sender := shortMatrixSender(string(ev.Sender))
|
||||
|
||||
switch ev.Type {
|
||||
case event.EventMessage:
|
||||
if body, ok := extractBody(ev); ok {
|
||||
return MatrixMessage{Sender: sender, Body: body, Timestamp: ts}, true
|
||||
}
|
||||
return MatrixMessage{}, false
|
||||
case event.EventEncrypted:
|
||||
if m.crypto != nil {
|
||||
decrypted, err := m.crypto.Decrypt(ctx, ev)
|
||||
if err == nil && decrypted != nil {
|
||||
if body, ok := extractBody(decrypted); ok {
|
||||
return MatrixMessage{Sender: sender, Body: body, Timestamp: ts}, true
|
||||
}
|
||||
}
|
||||
}
|
||||
return MatrixMessage{Sender: sender, Body: "[Verschlüsselte Nachricht]", Timestamp: ts}, true
|
||||
default:
|
||||
return MatrixMessage{}, false
|
||||
}
|
||||
}
|
||||
|
||||
func extractBody(ev *event.Event) (string, bool) {
|
||||
if ev == nil {
|
||||
return "", false
|
||||
}
|
||||
_ = ev.Content.ParseRaw(ev.Type)
|
||||
msg := ev.Content.AsMessage()
|
||||
if msg.MsgType != event.MsgText && msg.MsgType != event.MsgNotice {
|
||||
return "", false
|
||||
}
|
||||
body := strings.TrimSpace(msg.Body)
|
||||
if body == "" {
|
||||
return "", false
|
||||
}
|
||||
return body, true
|
||||
}
|
||||
|
||||
func shortMatrixSender(sender string) string {
|
||||
s := strings.TrimSpace(sender)
|
||||
if s == "" {
|
||||
return sender
|
||||
}
|
||||
if strings.HasPrefix(s, "@") {
|
||||
s = strings.TrimPrefix(s, "@")
|
||||
}
|
||||
if idx := strings.Index(s, ":"); idx > 0 {
|
||||
return s[:idx]
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user