push: implement parsing native notifications (#87)

This commit is contained in:
Tulir Asokan
2025-01-24 15:34:34 +02:00
committed by GitHub
parent b158ba6b8b
commit 823eda7589
3 changed files with 85 additions and 16 deletions
+6 -6
View File
@@ -10,12 +10,13 @@ require (
github.com/gotd/td v0.111.0
github.com/rs/zerolog v1.33.0
github.com/stretchr/testify v1.10.0
go.mau.fi/util v0.8.4-0.20250110124612-64d4dbbec957
github.com/tidwall/gjson v1.18.0
go.mau.fi/util v0.8.4
go.mau.fi/zerozap v0.1.1
go.uber.org/zap v1.27.0
golang.org/x/exp v0.0.0-20250103183323-7d7fa50e5329
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8
golang.org/x/net v0.34.0
maunium.net/go/mautrix v0.22.2-0.20250110154103-bbcb1904e268
maunium.net/go/mautrix v0.23.1-0.20250122131841-524379bdb327
)
require (
@@ -31,7 +32,7 @@ require (
github.com/gotd/neo v0.1.5 // indirect
github.com/klauspost/compress v1.17.11 // indirect
github.com/lib/pq v1.10.9 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-sqlite3 v1.14.24 // indirect
github.com/petermattis/goid v0.0.0-20241211131331-93ee7e083c43 // indirect
@@ -39,7 +40,6 @@ require (
github.com/rs/xid v1.6.0 // indirect
github.com/segmentio/asm v1.2.0 // indirect
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect
github.com/tidwall/gjson v1.18.0 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
github.com/tidwall/sjson v1.2.5 // indirect
@@ -59,4 +59,4 @@ require (
rsc.io/qr v0.2.0 // indirect
)
replace github.com/gotd/td => github.com/beeper/td v0.107.1-0.20241219153009-6e671c4e86b0
replace github.com/gotd/td => github.com/beeper/td v0.107.1-0.20250122125324-9af21bf4109e
+10 -9
View File
@@ -2,8 +2,8 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU=
github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU=
github.com/beeper/td v0.107.1-0.20241219153009-6e671c4e86b0 h1:+bLLCnRdnntmNGLvxigSlDPUOJlsqHw6cxTgNTGMGW4=
github.com/beeper/td v0.107.1-0.20241219153009-6e671c4e86b0/go.mod h1:5Db4K0d5B+vGIBpNVv2F0ABM14f0PcRJ+RQlKRnUcZQ=
github.com/beeper/td v0.107.1-0.20250122125324-9af21bf4109e h1:8qzwKf37vqg1rO6tPIWybxCXUygOGFjl+TA9rZrCDFE=
github.com/beeper/td v0.107.1-0.20250122125324-9af21bf4109e/go.mod h1:5Db4K0d5B+vGIBpNVv2F0ABM14f0PcRJ+RQlKRnUcZQ=
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/coder/websocket v1.8.12 h1:5bUXkEPPIbewrnkU8LTCLVaxi4N4J8ahufH2vlo4NAo=
@@ -38,8 +38,9 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
@@ -76,8 +77,8 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
github.com/yuin/goldmark v1.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic=
github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
go.mau.fi/util v0.8.4-0.20250110124612-64d4dbbec957 h1:tsLt3t6ARc55niz+JMgJy6U4sL210Z0K/nyxF09xT0E=
go.mau.fi/util v0.8.4-0.20250110124612-64d4dbbec957/go.mod h1:MOfGTs1CBuK6ERTcSL4lb5YU7/ujz09eOPVEDckuazY=
go.mau.fi/util v0.8.4 h1:mVKlJcXWfVo8ZW3f4vqtjGpqtZqJvX4ETekxawt2vnQ=
go.mau.fi/util v0.8.4/go.mod h1:MOfGTs1CBuK6ERTcSL4lb5YU7/ujz09eOPVEDckuazY=
go.mau.fi/zeroconfig v0.1.3 h1:As9wYDKmktjmNZW5i1vn8zvJlmGKHeVxHVIBMXsm4kM=
go.mau.fi/zeroconfig v0.1.3/go.mod h1:NcSJkf180JT+1IId76PcMuLTNa1CzsFFZ0nBygIQM70=
go.mau.fi/zerozap v0.1.1 h1:mxE/dW4wtkqBYOXOEEzXldk5qKB+ahsZXjoTGnvEhZQ=
@@ -96,8 +97,8 @@ go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
golang.org/x/exp v0.0.0-20250103183323-7d7fa50e5329 h1:9kj3STMvgqy3YA4VQXBrN7925ICMxD5wzMRcgA30588=
golang.org/x/exp v0.0.0-20250103183323-7d7fa50e5329/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 h1:yqrTHse8TCMW1M1ZCP+VAR/l0kKxwaAIqN/il7x4voA=
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU=
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -119,8 +120,8 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
maunium.net/go/mauflag v1.0.0 h1:YiaRc0tEI3toYtJMRIfjP+jklH45uDHtT80nUamyD4M=
maunium.net/go/mauflag v1.0.0/go.mod h1:nLivPOpTpHnpzEh8jEdSL9UqO9+/KBJFmNRlwKfkPeA=
maunium.net/go/mautrix v0.22.2-0.20250110154103-bbcb1904e268 h1:p+3TofdhqiVYIkLjgzidayg2XriGUEbj+nbWs3/UQbk=
maunium.net/go/mautrix v0.22.2-0.20250110154103-bbcb1904e268/go.mod h1:07i96D7BALyuAqxFhRzvaId8FC9NABgRQBPY5HWndf4=
maunium.net/go/mautrix v0.23.1-0.20250122131841-524379bdb327 h1:Fb1bAUNz3eEYI6jegWv1OLwWJQRy8TzvlrvZfS4qc2U=
maunium.net/go/mautrix v0.23.1-0.20250122131841-524379bdb327/go.mod h1:AGnnaz3ylGikUo1I1MJVn9QLsl2No1/ZNnGDyO0QD5s=
nhooyr.io/websocket v1.8.17 h1:KEVeLJkUywCKVsnLIDlD/5gtayKp8VoCkksHCGGfT9Y=
nhooyr.io/websocket v1.8.17/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c=
rsc.io/qr v0.2.0 h1:6vBLea5/NRMVTz8V66gipeLycZMl/+UlFmk8DvqQ6WY=
+69 -1
View File
@@ -2,17 +2,85 @@ package connector
import (
"context"
"crypto/rand"
"encoding/base64"
"encoding/json"
"fmt"
"github.com/gotd/td/bin"
"github.com/gotd/td/crypto"
"github.com/gotd/td/tg"
"github.com/tidwall/gjson"
"go.mau.fi/util/random"
"maunium.net/go/mautrix/bridgev2"
"maunium.net/go/mautrix/bridgev2/networkid"
)
var _ bridgev2.PushableNetworkAPI = (*TelegramClient)(nil)
var (
_ bridgev2.PushableNetworkAPI = (*TelegramClient)(nil)
_ bridgev2.PushParsingNetwork = (*TelegramConnector)(nil)
)
var PushAppSandbox = false
// TODO
type PushNotificationData map[string]any
func (tg *TelegramConnector) ParsePushNotification(ctx context.Context, data json.RawMessage) (networkid.UserLoginID, any, error) {
val := gjson.GetBytes(data, "p")
if val.Type != gjson.String {
return "", nil, fmt.Errorf("missing or invalid p field")
}
valBytes, err := base64.RawURLEncoding.DecodeString(val.Str)
if err != nil {
return "", nil, fmt.Errorf("failed to base64 decode p field: %w", err)
}
var em crypto.EncryptedMessage
err = em.DecodeWithoutCopy(&bin.Buffer{Buf: valBytes})
if err != nil {
return "", nil, fmt.Errorf("failed to decode auth key and message ID: %w", err)
}
userIDs, err := tg.Bridge.DB.UserLogin.GetAllUserIDsWithLogins(ctx)
if err != nil {
return "", nil, fmt.Errorf("failed to get users with logins: %w", err)
}
var matchingAuthKey *crypto.AuthKey
var userLoginID networkid.UserLoginID
UserLoop:
for _, userID := range userIDs {
user, err := tg.Bridge.GetExistingUserByMXID(ctx, userID)
if err != nil {
return "", nil, fmt.Errorf("failed to get user %s: %w", userID, err)
}
for _, login := range user.GetUserLogins() {
key := login.Metadata.(*UserLoginMetadata).PushEncryptionKey
if len(key) != 256 {
continue
}
authKey := crypto.Key(key).WithID()
if authKey.ID == em.AuthKeyID {
matchingAuthKey = &authKey
userLoginID = login.ID
break UserLoop
}
}
}
if matchingAuthKey == nil {
return "", nil, fmt.Errorf("no matching auth key found")
}
c := crypto.NewClientCipher(rand.Reader)
plaintext, err := c.DecryptRaw(*matchingAuthKey, &em)
if err != nil {
return userLoginID, nil, fmt.Errorf("failed to decrypt payload: %w", err)
}
pmd := make(PushNotificationData)
err = json.Unmarshal(plaintext, &pmd)
if err != nil {
return userLoginID, nil, fmt.Errorf("failed to unmarshal decrypted payload: %w", err)
}
return userLoginID, pmd, nil
}
func (t *TelegramClient) RegisterPushNotifications(ctx context.Context, pushType bridgev2.PushType, token string) error {
meta := t.userLogin.Metadata.(*UserLoginMetadata)
if meta.PushEncryptionKey == nil {