diff --git a/.github/ISSUE_TEMPLATE/bug.md b/.github/ISSUE_TEMPLATE/bug.md index cba1054..c10630f 100644 --- a/.github/ISSUE_TEMPLATE/bug.md +++ b/.github/ISSUE_TEMPLATE/bug.md @@ -11,8 +11,7 @@ type: Bug ### Checklist - + * [ ] This is an actual bug, not just a setup issue (see the [troubleshooting docs](https://docs.mau.fi/bridges/general/troubleshooting.html) or ask in the Matrix room for setup help). * [ ] I am certain that sufficient information is included. Ask in the Matrix room first if not. -* [ ] The bug is still present on the main branch. The `!signal version` command output is: `` diff --git a/go.mod b/go.mod index 931af45..1106eb6 100644 --- a/go.mod +++ b/go.mod @@ -11,17 +11,16 @@ require ( github.com/emersion/go-vcard v0.0.0-20241024213814-c9703dde27ff github.com/google/uuid v1.6.0 github.com/mattn/go-pointer v0.0.1 - github.com/rs/zerolog v1.35.1 + github.com/rs/zerolog v1.35.0 github.com/stretchr/testify v1.11.1 github.com/tidwall/gjson v1.18.0 - go.mau.fi/util v0.9.9-0.20260511124621-9241e81bdf25 + go.mau.fi/util v0.9.8 golang.org/x/crypto v0.50.0 golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f golang.org/x/net v0.53.0 - golang.org/x/sync v0.20.0 google.golang.org/protobuf v1.36.11 gopkg.in/yaml.v3 v3.0.1 - maunium.net/go/mautrix v0.27.1-0.20260513120123-5fba7e3afae4 + maunium.net/go/mautrix v0.27.0 ) require ( @@ -32,7 +31,7 @@ require ( github.com/lib/pq v1.12.3 // 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.44 // indirect + github.com/mattn/go-sqlite3 v1.14.42 // indirect github.com/petermattis/goid v0.0.0-20260330135022-df67b199bc81 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect @@ -44,6 +43,7 @@ require ( github.com/yuin/goldmark v1.8.2 // indirect go.mau.fi/zeroconfig v0.2.0 // indirect golang.org/x/mod v0.35.0 // indirect + golang.org/x/sync v0.20.0 // indirect golang.org/x/sys v0.43.0 // indirect golang.org/x/text v0.36.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect diff --git a/go.sum b/go.sum index 2f02866..0f27daa 100644 --- a/go.sum +++ b/go.sum @@ -30,8 +30,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-pointer v0.0.1 h1:n+XhsuGeVO6MEAp7xyEukFINEa+Quek5psIR/ylA6o0= github.com/mattn/go-pointer v0.0.1/go.mod h1:2zXcozF6qYGgmsG+SeTZz3oAbFLdD3OWqnUbNvJZAlc= -github.com/mattn/go-sqlite3 v1.14.44 h1:3VSe+xafpbzsLbdr2AWlAZk9yRHiBhTBakioXaCKTF8= -github.com/mattn/go-sqlite3 v1.14.44/go.mod h1:pjEuOr8IwzLJP2MfGeTb0A35jauH+C2kbHKBr7yXKVQ= +github.com/mattn/go-sqlite3 v1.14.42 h1:MigqEP4ZmHw3aIdIT7T+9TLa90Z6smwcthx+Azv4Cgo= +github.com/mattn/go-sqlite3 v1.14.42/go.mod h1:pjEuOr8IwzLJP2MfGeTb0A35jauH+C2kbHKBr7yXKVQ= github.com/petermattis/goid v0.0.0-20260330135022-df67b199bc81 h1:WDsQxOJDy0N1VRAjXLpi8sCEZRSGarLWQevDxpTBRrM= github.com/petermattis/goid v0.0.0-20260330135022-df67b199bc81/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= @@ -42,8 +42,8 @@ github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjR github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU= github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= -github.com/rs/zerolog v1.35.1 h1:m7xQeoiLIiV0BCEY4Hs+j2NG4Gp2o2KPKmhnnLiazKI= -github.com/rs/zerolog v1.35.1/go.mod h1:EjML9kdfa/RMA7h/6z6pYmq1ykOuA8/mjWaEvGI+jcw= +github.com/rs/zerolog v1.35.0 h1:VD0ykx7HMiMJytqINBsKcbLS+BJ4WYjz+05us+LRTdI= +github.com/rs/zerolog v1.35.0/go.mod h1:EjML9kdfa/RMA7h/6z6pYmq1ykOuA8/mjWaEvGI+jcw= github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0= github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= @@ -61,8 +61,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.8.2 h1:kEGpgqJXdgbkhcOgBxkC0X0PmoPG1ZyoZ117rDVp4zE= github.com/yuin/goldmark v1.8.2/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= -go.mau.fi/util v0.9.9-0.20260511124621-9241e81bdf25 h1:YPEmc+li7TF6C9AdRTcSLMb6yCHdF27/wNT7kFLIVNg= -go.mau.fi/util v0.9.9-0.20260511124621-9241e81bdf25/go.mod h1:jE9FfhbgEgAwxei6lomO9v8zdCIATcquONUu4vjRwSs= +go.mau.fi/util v0.9.8 h1:+/jf8eM2dAT2wx9UidmaneH28r/CSCKCniCyby1qWz8= +go.mau.fi/util v0.9.8/go.mod h1:up/5mbzH2M1pSBNXqRxODn8dg/hEKbLJu92W4/SNAX0= go.mau.fi/zeroconfig v0.2.0 h1:e/OGEERqVRRKlgaro7E6bh8xXiKFSXB3eNNIud7FUjU= go.mau.fi/zeroconfig v0.2.0/go.mod h1:J0Vn0prHNOm493oZoQ84kq83ZaNCYZnq+noI1b1eN8w= golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI= @@ -91,5 +91,5 @@ 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.27.1-0.20260513120123-5fba7e3afae4 h1:zNC9eVAhw8FhKpM3AxNAh/iy75UEYX91uJUvqqAYlvo= -maunium.net/go/mautrix v0.27.1-0.20260513120123-5fba7e3afae4/go.mod h1:3sOGhXi3P1V6/NruTA0gujkvTypXVUraWktCuTGyDuM= +maunium.net/go/mautrix v0.27.0 h1:yfEYwoIluVWkofUgbZl9gP4i5nQTF+QNsxtb+r5bKlM= +maunium.net/go/mautrix v0.27.0/go.mod h1:7QpEQiTy6p4LHkXXaZI+N46tGYy8HMhD0JjzZAFoFWs= diff --git a/pkg/connector/capabilities.go b/pkg/connector/capabilities.go index 5eab6a8..e791324 100644 --- a/pkg/connector/capabilities.go +++ b/pkg/connector/capabilities.go @@ -38,7 +38,7 @@ func supportedIfFFmpeg() event.CapabilitySupportLevel { } func capID() string { - base := "fi.mau.signal.capabilities.2026_05_12" + base := "fi.mau.signal.capabilities.2025_12_09" if ffmpeg.Supported() { return base + "+ffmpeg" } @@ -111,8 +111,7 @@ var signalCaps = &event.RoomFeatures{ }, event.CapMsgSticker: { MimeTypes: map[string]event.CapabilitySupportLevel{ - // Signal clients will only render static webp, so apng is preferred - "image/webp": event.CapLevelPartialSupport, + "image/webp": event.CapLevelFullySupported, "image/png": event.CapLevelFullySupported, "image/apng": event.CapLevelFullySupported, "image/gif": supportedIfFFmpeg(), @@ -212,7 +211,6 @@ var signalGeneralCaps = &bridgev2.NetworkGeneralCapabilities{ AggressiveUpdateInfo: true, ImplicitReadReceipts: true, Provisioning: bridgev2.ProvisioningCapabilities{ - ImagePackImport: true, ResolveIdentifier: bridgev2.ResolveIdentifierCapabilities{ CreateDM: true, LookupPhone: true, @@ -237,5 +235,5 @@ func (s *SignalConnector) GetCapabilities() *bridgev2.NetworkGeneralCapabilities } func (s *SignalConnector) GetBridgeInfoVersion() (info, capabilities int) { - return 1, 8 + return 1, 7 } diff --git a/pkg/connector/client.go b/pkg/connector/client.go index 4fcf188..17ee216 100644 --- a/pkg/connector/client.go +++ b/pkg/connector/client.go @@ -27,7 +27,6 @@ import ( "maunium.net/go/mautrix/bridgev2" "maunium.net/go/mautrix/bridgev2/networkid" "maunium.net/go/mautrix/bridgev2/status" - "maunium.net/go/mautrix/event" "go.mau.fi/mautrix-signal/pkg/signalid" "go.mau.fi/mautrix-signal/pkg/signalmeow" @@ -47,7 +46,6 @@ type SignalClient struct { var ( _ bridgev2.NetworkAPI = (*SignalClient)(nil) _ bridgev2.BackgroundSyncingNetworkAPI = (*SignalClient)(nil) - _ bridgev2.StickerImportingNetworkAPI = (*SignalClient)(nil) ) var pushCfg = &bridgev2.PushConfig{ @@ -78,14 +76,6 @@ func (s *SignalClient) RegisterPushNotifications(ctx context.Context, pushType b } } -func (s *SignalClient) DownloadImagePack(ctx context.Context, url string) (*bridgev2.ImportedImagePack, error) { - return s.Main.MsgConv.DownloadImagePack(ctx, url) -} - -func (s *SignalClient) ListImagePacks(ctx context.Context) ([]*event.ImagePackMetadata, error) { - return []*event.ImagePackMetadata{}, nil -} - func (s *SignalClient) LogoutRemote(ctx context.Context) { if s.Client == nil { return diff --git a/pkg/connector/directmedia.go b/pkg/connector/directmedia.go index 05e2a07..0877d66 100644 --- a/pkg/connector/directmedia.go +++ b/pkg/connector/directmedia.go @@ -4,6 +4,7 @@ import ( "context" "encoding/base64" "fmt" + "io" "os" "maunium.net/go/mautrix/bridgev2" @@ -29,7 +30,6 @@ func (s *SignalConnector) Download(ctx context.Context, mediaID networkid.MediaI return nil, fmt.Errorf("failed to parse direct media id: %w", err) } - var rawDataResp []byte switch info := info.(type) { case *signalid.DirectMediaAttachment: log.Info(). @@ -76,11 +76,18 @@ func (s *SignalConnector) Download(ctx context.Context, mediaID networkid.MediaI return nil, fmt.Errorf("failed to to get group master key: %w", err) } - rawDataResp, err = client.Client.DownloadGroupAvatar(ctx, info.GroupAvatarPath, groupMasterKey) - if err != nil { - log.Err(err).Msg("Direct download failed") - return nil, err - } + return &mediaproxy.GetMediaResponseCallback{ + Callback: func(w io.Writer) (int64, error) { + data, err := client.Client.DownloadGroupAvatar(ctx, info.GroupAvatarPath, groupMasterKey) + if err != nil { + log.Err(err).Msg("Direct download failed") + return 0, err + } + + _, err = w.Write(data) + return int64(len(data)), err + }, + }, nil case *signalid.DirectMediaProfileAvatar: log.Info(). Stringer("user_id", info.UserID). @@ -104,27 +111,19 @@ func (s *SignalConnector) Download(ctx context.Context, mediaID networkid.MediaI return nil, fmt.Errorf("profile key not found") } - rawDataResp, err = client.Client.DownloadUserAvatar(ctx, info.ProfileAvatarPath, *profileKey) - if err != nil { - log.Err(err).Msg("Direct download failed") - return nil, err - } - case *signalid.DirectMediaSticker: - log.Info(). - Hex("pack_id", info.PackID). - Uint32("sticker_id", info.StickerID). - Msg("Direct downloading sticker") + return &mediaproxy.GetMediaResponseCallback{ + Callback: func(w io.Writer) (int64, error) { + data, err := client.Client.DownloadUserAvatar(ctx, info.ProfileAvatarPath, *profileKey) + if err != nil { + log.Err(err).Msg("Direct download failed") + return 0, err + } - rawDataResp, err = signalmeow.DownloadStickerPackItem(ctx, info.PackID, info.PackKey, info.StickerID) - if err != nil { - log.Err(err).Msg("Direct download failed") - return nil, err - } + _, err = w.Write(data) + return int64(len(data)), err + }, + }, nil default: return nil, fmt.Errorf("no downloader for direct media type: %T", info) } - if rawDataResp == nil { - return nil, fmt.Errorf("unexpected fallthrough with no data") - } - return mediaproxy.GetMediaResponseRawData(rawDataResp), nil } diff --git a/pkg/libsignalgo/identitykeystore.go b/pkg/libsignalgo/identitykeystore.go index ba26f06..43941da 100644 --- a/pkg/libsignalgo/identitykeystore.go +++ b/pkg/libsignalgo/identitykeystore.go @@ -159,11 +159,11 @@ func signal_destroy_identity_key_store_callback(storeCtx unsafe.Pointer) { func (ctx *CallbackContext) wrapIdentityKeyStore(store IdentityKeyStore) C.SignalConstPointerFfiIdentityKeyStoreStruct { return C.SignalConstPointerFfiIdentityKeyStoreStruct{&C.SignalIdentityKeyStore{ ctx: wrapStore(ctx, store), - get_local_identity_key_pair: C.SignalFfiIdentityKeyStoreGetLocalIdentityKeyPair(C.signal_get_identity_key_pair_callback), - get_local_registration_id: C.SignalFfiIdentityKeyStoreGetLocalRegistrationId(C.signal_get_local_registration_id_callback), - get_identity_key: C.SignalFfiIdentityKeyStoreGetIdentityKey(C.signal_get_identity_key_callback), - save_identity_key: C.SignalFfiIdentityKeyStoreSaveIdentityKey(C.signal_save_identity_key_callback), - is_trusted_identity: C.SignalFfiIdentityKeyStoreIsTrustedIdentity(C.signal_is_trusted_identity_callback), - destroy: C.SignalFfiIdentityKeyStoreDestroy(C.signal_destroy_identity_key_store_callback), + get_local_identity_key_pair: C.SignalFfiBridgeIdentityKeyStoreGetLocalIdentityKeyPair(C.signal_get_identity_key_pair_callback), + get_local_registration_id: C.SignalFfiBridgeIdentityKeyStoreGetLocalRegistrationId(C.signal_get_local_registration_id_callback), + get_identity_key: C.SignalFfiBridgeIdentityKeyStoreGetIdentityKey(C.signal_get_identity_key_callback), + save_identity_key: C.SignalFfiBridgeIdentityKeyStoreSaveIdentityKey(C.signal_save_identity_key_callback), + is_trusted_identity: C.SignalFfiBridgeIdentityKeyStoreIsTrustedIdentity(C.signal_is_trusted_identity_callback), + destroy: C.SignalFfiBridgeIdentityKeyStoreDestroy(C.signal_destroy_identity_key_store_callback), }} } diff --git a/pkg/libsignalgo/kyberprekeystore.go b/pkg/libsignalgo/kyberprekeystore.go index 9deea17..ebb5a9f 100644 --- a/pkg/libsignalgo/kyberprekeystore.go +++ b/pkg/libsignalgo/kyberprekeystore.go @@ -77,9 +77,9 @@ func signal_destroy_kyber_pre_key_store_callback(storeCtx unsafe.Pointer) { func (ctx *CallbackContext) wrapKyberPreKeyStore(store KyberPreKeyStore) C.SignalConstPointerFfiKyberPreKeyStoreStruct { return C.SignalConstPointerFfiKyberPreKeyStoreStruct{&C.SignalKyberPreKeyStore{ ctx: wrapStore(ctx, store), - load_kyber_pre_key: C.SignalFfiKyberPreKeyStoreLoadKyberPreKey(C.signal_load_kyber_pre_key_callback), - store_kyber_pre_key: C.SignalFfiKyberPreKeyStoreStoreKyberPreKey(C.signal_store_kyber_pre_key_callback), - mark_kyber_pre_key_used: C.SignalFfiKyberPreKeyStoreMarkKyberPreKeyUsed(C.signal_mark_kyber_pre_key_used_callback), - destroy: C.SignalFfiKyberPreKeyStoreDestroy(C.signal_destroy_kyber_pre_key_store_callback), + load_kyber_pre_key: C.SignalFfiBridgeKyberPreKeyStoreLoadKyberPreKey(C.signal_load_kyber_pre_key_callback), + store_kyber_pre_key: C.SignalFfiBridgeKyberPreKeyStoreStoreKyberPreKey(C.signal_store_kyber_pre_key_callback), + mark_kyber_pre_key_used: C.SignalFfiBridgeKyberPreKeyStoreMarkKyberPreKeyUsed(C.signal_mark_kyber_pre_key_used_callback), + destroy: C.SignalFfiBridgeKyberPreKeyStoreDestroy(C.signal_destroy_kyber_pre_key_store_callback), }} } diff --git a/pkg/libsignalgo/libsignal b/pkg/libsignalgo/libsignal index bbc1688..b58bd7d 160000 --- a/pkg/libsignalgo/libsignal +++ b/pkg/libsignalgo/libsignal @@ -1 +1 @@ -Subproject commit bbc16886cae2feab1cd1fe271ccc651e8860ce96 +Subproject commit b58bd7d5dfa0a391486df4210fd83bab96b9b479 diff --git a/pkg/libsignalgo/libsignal-ffi.h b/pkg/libsignalgo/libsignal-ffi.h index b75462a..fe3bf52 100644 --- a/pkg/libsignalgo/libsignal-ffi.h +++ b/pkg/libsignalgo/libsignal-ffi.h @@ -629,27 +629,6 @@ typedef struct { const SignalHttpRequest *raw; } SignalConstPointerHttpRequest; -/** - * The fixed-width binary representation of a ServiceId. - * - * Rarely used. The variable-width format that privileges ACIs is preferred. - */ -typedef uint8_t SignalServiceIdFixedWidthBinaryBytes[17]; - -typedef struct { - const uint32_t *base; - size_t length; -} SignalBorrowedSliceOfu32; - -typedef struct { - const SignalCiphertextMessage *raw; -} SignalConstPointerCiphertextMessage; - -typedef struct { - const SignalConstPointerCiphertextMessage *base; - size_t length; -} SignalBorrowedSliceOfConstPointerCiphertextMessage; - /** * A wrapper type for raw UUIDs, because C treats arrays specially in argument position. */ @@ -657,6 +636,13 @@ typedef struct { uint8_t bytes[16]; } SignalUuid; +/** + * The fixed-width binary representation of a ServiceId. + * + * Rarely used. The variable-width format that privileges ACIs is preferred. + */ +typedef uint8_t SignalServiceIdFixedWidthBinaryBytes[17]; + typedef struct { SignalPrivateKey *raw; } SignalMutPointerPrivateKey; @@ -768,6 +754,10 @@ typedef struct { const SignalPlaintextContent *raw; } SignalConstPointerPlaintextContent; +typedef struct { + const SignalCiphertextMessage *raw; +} SignalConstPointerCiphertextMessage; + typedef struct { SignalConnectionInfo *raw; } SignalMutPointerConnectionInfo; @@ -792,18 +782,20 @@ typedef struct { SignalSessionRecord *raw; } SignalMutPointerSessionRecord; -typedef int (*SignalFfiSessionStoreLoadSession)(void *ctx, SignalMutPointerSessionRecord *out, SignalMutPointerProtocolAddress address); +typedef int (*SignalFfiBridgeSessionStoreLoadSession)(void *ctx, SignalMutPointerSessionRecord *out, SignalMutPointerProtocolAddress address); -typedef int (*SignalFfiSessionStoreStoreSession)(void *ctx, SignalMutPointerProtocolAddress address, SignalMutPointerSessionRecord record); +typedef int (*SignalFfiBridgeSessionStoreStoreSession)(void *ctx, SignalMutPointerProtocolAddress address, SignalMutPointerSessionRecord record); -typedef void (*SignalFfiSessionStoreDestroy)(void *ctx); +typedef void (*SignalFfiBridgeSessionStoreDestroy)(void *ctx); typedef struct { void *ctx; - SignalFfiSessionStoreLoadSession load_session; - SignalFfiSessionStoreStoreSession store_session; - SignalFfiSessionStoreDestroy destroy; -} SignalSessionStore; + SignalFfiBridgeSessionStoreLoadSession load_session; + SignalFfiBridgeSessionStoreStoreSession store_session; + SignalFfiBridgeSessionStoreDestroy destroy; +} SignalFfiBridgeSessionStoreStruct; + +typedef SignalFfiBridgeSessionStoreStruct SignalSessionStore; typedef struct { const SignalSessionStore *raw; @@ -818,27 +810,29 @@ typedef struct { SignalMutPointerPublicKey second; } SignalPairOfMutPointerPrivateKeyMutPointerPublicKey; -typedef int (*SignalFfiIdentityKeyStoreGetLocalIdentityKeyPair)(void *ctx, SignalPairOfMutPointerPrivateKeyMutPointerPublicKey *out); +typedef int (*SignalFfiBridgeIdentityKeyStoreGetLocalIdentityKeyPair)(void *ctx, SignalPairOfMutPointerPrivateKeyMutPointerPublicKey *out); -typedef int (*SignalFfiIdentityKeyStoreGetLocalRegistrationId)(void *ctx, uint32_t *out); +typedef int (*SignalFfiBridgeIdentityKeyStoreGetLocalRegistrationId)(void *ctx, uint32_t *out); -typedef int (*SignalFfiIdentityKeyStoreGetIdentityKey)(void *ctx, SignalMutPointerPublicKey *out, SignalMutPointerProtocolAddress address); +typedef int (*SignalFfiBridgeIdentityKeyStoreGetIdentityKey)(void *ctx, SignalMutPointerPublicKey *out, SignalMutPointerProtocolAddress address); -typedef int (*SignalFfiIdentityKeyStoreSaveIdentityKey)(void *ctx, uint8_t *out, SignalMutPointerProtocolAddress address, SignalMutPointerPublicKey public_key); +typedef int (*SignalFfiBridgeIdentityKeyStoreSaveIdentityKey)(void *ctx, uint8_t *out, SignalMutPointerProtocolAddress address, SignalMutPointerPublicKey public_key); -typedef int (*SignalFfiIdentityKeyStoreIsTrustedIdentity)(void *ctx, bool *out, SignalMutPointerProtocolAddress address, SignalMutPointerPublicKey public_key, uint32_t direction); +typedef int (*SignalFfiBridgeIdentityKeyStoreIsTrustedIdentity)(void *ctx, bool *out, SignalMutPointerProtocolAddress address, SignalMutPointerPublicKey public_key, uint32_t direction); -typedef void (*SignalFfiIdentityKeyStoreDestroy)(void *ctx); +typedef void (*SignalFfiBridgeIdentityKeyStoreDestroy)(void *ctx); typedef struct { void *ctx; - SignalFfiIdentityKeyStoreGetLocalIdentityKeyPair get_local_identity_key_pair; - SignalFfiIdentityKeyStoreGetLocalRegistrationId get_local_registration_id; - SignalFfiIdentityKeyStoreGetIdentityKey get_identity_key; - SignalFfiIdentityKeyStoreSaveIdentityKey save_identity_key; - SignalFfiIdentityKeyStoreIsTrustedIdentity is_trusted_identity; - SignalFfiIdentityKeyStoreDestroy destroy; -} SignalIdentityKeyStore; + SignalFfiBridgeIdentityKeyStoreGetLocalIdentityKeyPair get_local_identity_key_pair; + SignalFfiBridgeIdentityKeyStoreGetLocalRegistrationId get_local_registration_id; + SignalFfiBridgeIdentityKeyStoreGetIdentityKey get_identity_key; + SignalFfiBridgeIdentityKeyStoreSaveIdentityKey save_identity_key; + SignalFfiBridgeIdentityKeyStoreIsTrustedIdentity is_trusted_identity; + SignalFfiBridgeIdentityKeyStoreDestroy destroy; +} SignalFfiBridgeIdentityKeyStoreStruct; + +typedef SignalFfiBridgeIdentityKeyStoreStruct SignalIdentityKeyStore; typedef struct { const SignalIdentityKeyStore *raw; @@ -852,21 +846,23 @@ typedef struct { SignalPreKeyRecord *raw; } SignalMutPointerPreKeyRecord; -typedef int (*SignalFfiPreKeyStoreLoadPreKey)(void *ctx, SignalMutPointerPreKeyRecord *out, uint32_t id); +typedef int (*SignalFfiBridgePreKeyStoreLoadPreKey)(void *ctx, SignalMutPointerPreKeyRecord *out, uint32_t id); -typedef int (*SignalFfiPreKeyStoreStorePreKey)(void *ctx, uint32_t id, SignalMutPointerPreKeyRecord record); +typedef int (*SignalFfiBridgePreKeyStoreStorePreKey)(void *ctx, uint32_t id, SignalMutPointerPreKeyRecord record); -typedef int (*SignalFfiPreKeyStoreRemovePreKey)(void *ctx, uint32_t id); +typedef int (*SignalFfiBridgePreKeyStoreRemovePreKey)(void *ctx, uint32_t id); -typedef void (*SignalFfiPreKeyStoreDestroy)(void *ctx); +typedef void (*SignalFfiBridgePreKeyStoreDestroy)(void *ctx); typedef struct { void *ctx; - SignalFfiPreKeyStoreLoadPreKey load_pre_key; - SignalFfiPreKeyStoreStorePreKey store_pre_key; - SignalFfiPreKeyStoreRemovePreKey remove_pre_key; - SignalFfiPreKeyStoreDestroy destroy; -} SignalPreKeyStore; + SignalFfiBridgePreKeyStoreLoadPreKey load_pre_key; + SignalFfiBridgePreKeyStoreStorePreKey store_pre_key; + SignalFfiBridgePreKeyStoreRemovePreKey remove_pre_key; + SignalFfiBridgePreKeyStoreDestroy destroy; +} SignalFfiBridgePreKeyStoreStruct; + +typedef SignalFfiBridgePreKeyStoreStruct SignalPreKeyStore; typedef struct { const SignalPreKeyStore *raw; @@ -876,18 +872,20 @@ typedef struct { SignalSignedPreKeyRecord *raw; } SignalMutPointerSignedPreKeyRecord; -typedef int (*SignalFfiSignedPreKeyStoreLoadSignedPreKey)(void *ctx, SignalMutPointerSignedPreKeyRecord *out, uint32_t id); +typedef int (*SignalFfiBridgeSignedPreKeyStoreLoadSignedPreKey)(void *ctx, SignalMutPointerSignedPreKeyRecord *out, uint32_t id); -typedef int (*SignalFfiSignedPreKeyStoreStoreSignedPreKey)(void *ctx, uint32_t id, SignalMutPointerSignedPreKeyRecord record); +typedef int (*SignalFfiBridgeSignedPreKeyStoreStoreSignedPreKey)(void *ctx, uint32_t id, SignalMutPointerSignedPreKeyRecord record); -typedef void (*SignalFfiSignedPreKeyStoreDestroy)(void *ctx); +typedef void (*SignalFfiBridgeSignedPreKeyStoreDestroy)(void *ctx); typedef struct { void *ctx; - SignalFfiSignedPreKeyStoreLoadSignedPreKey load_signed_pre_key; - SignalFfiSignedPreKeyStoreStoreSignedPreKey store_signed_pre_key; - SignalFfiSignedPreKeyStoreDestroy destroy; -} SignalSignedPreKeyStore; + SignalFfiBridgeSignedPreKeyStoreLoadSignedPreKey load_signed_pre_key; + SignalFfiBridgeSignedPreKeyStoreStoreSignedPreKey store_signed_pre_key; + SignalFfiBridgeSignedPreKeyStoreDestroy destroy; +} SignalFfiBridgeSignedPreKeyStoreStruct; + +typedef SignalFfiBridgeSignedPreKeyStoreStruct SignalSignedPreKeyStore; typedef struct { const SignalSignedPreKeyStore *raw; @@ -897,21 +895,23 @@ typedef struct { SignalKyberPreKeyRecord *raw; } SignalMutPointerKyberPreKeyRecord; -typedef int (*SignalFfiKyberPreKeyStoreLoadKyberPreKey)(void *ctx, SignalMutPointerKyberPreKeyRecord *out, uint32_t id); +typedef int (*SignalFfiBridgeKyberPreKeyStoreLoadKyberPreKey)(void *ctx, SignalMutPointerKyberPreKeyRecord *out, uint32_t id); -typedef int (*SignalFfiKyberPreKeyStoreStoreKyberPreKey)(void *ctx, uint32_t id, SignalMutPointerKyberPreKeyRecord record); +typedef int (*SignalFfiBridgeKyberPreKeyStoreStoreKyberPreKey)(void *ctx, uint32_t id, SignalMutPointerKyberPreKeyRecord record); -typedef int (*SignalFfiKyberPreKeyStoreMarkKyberPreKeyUsed)(void *ctx, uint32_t id, uint32_t ec_prekey_id, SignalMutPointerPublicKey base_key); +typedef int (*SignalFfiBridgeKyberPreKeyStoreMarkKyberPreKeyUsed)(void *ctx, uint32_t id, uint32_t ec_prekey_id, SignalMutPointerPublicKey base_key); -typedef void (*SignalFfiKyberPreKeyStoreDestroy)(void *ctx); +typedef void (*SignalFfiBridgeKyberPreKeyStoreDestroy)(void *ctx); typedef struct { void *ctx; - SignalFfiKyberPreKeyStoreLoadKyberPreKey load_kyber_pre_key; - SignalFfiKyberPreKeyStoreStoreKyberPreKey store_kyber_pre_key; - SignalFfiKyberPreKeyStoreMarkKyberPreKeyUsed mark_kyber_pre_key_used; - SignalFfiKyberPreKeyStoreDestroy destroy; -} SignalKyberPreKeyStore; + SignalFfiBridgeKyberPreKeyStoreLoadKyberPreKey load_kyber_pre_key; + SignalFfiBridgeKyberPreKeyStoreStoreKyberPreKey store_kyber_pre_key; + SignalFfiBridgeKyberPreKeyStoreMarkKyberPreKeyUsed mark_kyber_pre_key_used; + SignalFfiBridgeKyberPreKeyStoreDestroy destroy; +} SignalFfiBridgeKyberPreKeyStoreStruct; + +typedef SignalFfiBridgeKyberPreKeyStoreStruct SignalKyberPreKeyStore; typedef struct { const SignalKyberPreKeyStore *raw; @@ -1047,18 +1047,20 @@ typedef struct { SignalSenderKeyRecord *raw; } SignalMutPointerSenderKeyRecord; -typedef int (*SignalFfiSenderKeyStoreLoadSenderKey)(void *ctx, SignalMutPointerSenderKeyRecord *out, SignalMutPointerProtocolAddress sender, SignalUuid distribution_id); +typedef int (*SignalFfiBridgeSenderKeyStoreLoadSenderKey)(void *ctx, SignalMutPointerSenderKeyRecord *out, SignalMutPointerProtocolAddress sender, SignalUuid distribution_id); -typedef int (*SignalFfiSenderKeyStoreStoreSenderKey)(void *ctx, SignalMutPointerProtocolAddress sender, SignalUuid distribution_id, SignalMutPointerSenderKeyRecord record); +typedef int (*SignalFfiBridgeSenderKeyStoreStoreSenderKey)(void *ctx, SignalMutPointerProtocolAddress sender, SignalUuid distribution_id, SignalMutPointerSenderKeyRecord record); -typedef void (*SignalFfiSenderKeyStoreDestroy)(void *ctx); +typedef void (*SignalFfiBridgeSenderKeyStoreDestroy)(void *ctx); typedef struct { void *ctx; - SignalFfiSenderKeyStoreLoadSenderKey load_sender_key; - SignalFfiSenderKeyStoreStoreSenderKey store_sender_key; - SignalFfiSenderKeyStoreDestroy destroy; -} SignalSenderKeyStore; + SignalFfiBridgeSenderKeyStoreLoadSenderKey load_sender_key; + SignalFfiBridgeSenderKeyStoreStoreSenderKey store_sender_key; + SignalFfiBridgeSenderKeyStoreDestroy destroy; +} SignalFfiBridgeSenderKeyStoreStruct; + +typedef SignalFfiBridgeSenderKeyStoreStruct SignalSenderKeyStore; typedef struct { const SignalSenderKeyStore *raw; @@ -1115,11 +1117,6 @@ typedef struct { SignalFfiLoggerDestroy destroy; } SignalFfiLoggerStruct; -typedef struct { - SignalOwnedBuffer first; - SignalOwnedBuffer second; -} SignalPairOfOwnedBufferOfc_ucharOwnedBufferOfc_uchar; - /** * A C callback used to report the results of Rust futures. * @@ -1130,10 +1127,10 @@ typedef struct { * completed once. */ typedef struct { - void (*complete)(SignalFfiError *error, const SignalPairOfOwnedBufferOfc_ucharOwnedBufferOfc_uchar *result, const void *context); + void (*complete)(SignalFfiError *error, const SignalOwnedBuffer *result, const void *context); const void *context; SignalCancellationId cancellation_id; -} SignalCPromisePairOfOwnedBufferOfc_ucharOwnedBufferOfc_uchar; +} SignalCPromiseOwnedBufferOfc_uchar; typedef struct { const SignalUnauthenticatedChatConnection *raw; @@ -1203,18 +1200,20 @@ typedef struct { const SignalMessageBackupValidationOutcome *raw; } SignalConstPointerMessageBackupValidationOutcome; -typedef int (*SignalFfiInputStreamRead)(void *ctx, size_t *out, SignalBorrowedMutableBuffer buf); +typedef int (*SignalFfiBridgeInputStreamRead)(void *ctx, size_t *out, SignalBorrowedMutableBuffer buf); -typedef int (*SignalFfiInputStreamSkip)(void *ctx, uint64_t amount); +typedef int (*SignalFfiBridgeInputStreamSkip)(void *ctx, uint64_t amount); -typedef void (*SignalFfiInputStreamDestroy)(void *ctx); +typedef void (*SignalFfiBridgeInputStreamDestroy)(void *ctx); typedef struct { void *ctx; - SignalFfiInputStreamRead read; - SignalFfiInputStreamSkip skip; - SignalFfiInputStreamDestroy destroy; -} SignalInputStream; + SignalFfiBridgeInputStreamRead read; + SignalFfiBridgeInputStreamSkip skip; + SignalFfiBridgeInputStreamDestroy destroy; +} SignalFfiBridgeInputStreamStruct; + +typedef SignalFfiBridgeInputStreamStruct SignalInputStream; typedef struct { const SignalInputStream *raw; @@ -1648,7 +1647,9 @@ typedef struct { SignalValidatingMac *raw; } SignalMutPointerValidatingMac; -typedef SignalInputStream SignalSyncInputStream; +typedef SignalFfiBridgeInputStreamStruct SignalFfiBridgeSyncInputStreamStruct; + +typedef SignalFfiBridgeSyncInputStreamStruct SignalSyncInputStream; typedef struct { const SignalSyncInputStream *raw; @@ -1736,10 +1737,6 @@ SignalFfiError *signal_authenticated_chat_connection_preconnect(SignalCPromisebo SignalFfiError *signal_authenticated_chat_connection_send(SignalCPromiseFfiChatResponse *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerAuthenticatedChatConnection chat, SignalConstPointerHttpRequest http_request, uint32_t timeout_millis); -SignalFfiError *signal_authenticated_chat_connection_send_message(SignalCPromisebool *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerAuthenticatedChatConnection chat, const SignalServiceIdFixedWidthBinaryBytes *destination, uint64_t timestamp, SignalBorrowedSliceOfu32 device_ids, SignalBorrowedSliceOfu32 registration_ids, SignalBorrowedSliceOfConstPointerCiphertextMessage contents, bool online_only, bool is_urgent); - -SignalFfiError *signal_authenticated_chat_connection_send_sync_message(SignalCPromisebool *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerAuthenticatedChatConnection chat, uint64_t timestamp, SignalBorrowedSliceOfu32 device_ids, SignalBorrowedSliceOfu32 registration_ids, SignalBorrowedSliceOfConstPointerCiphertextMessage contents, bool is_urgent); - SignalFfiError *signal_backup_auth_credential_check_valid_contents(SignalBorrowedBuffer params_bytes); SignalFfiError *signal_backup_auth_credential_get_backup_id(uint8_t (*out)[16], SignalBorrowedBuffer credential_bytes); @@ -1900,7 +1897,7 @@ SignalFfiError *signal_create_call_link_credential_request_issue_deterministic(S SignalFfiError *signal_create_call_link_credential_response_check_valid_contents(SignalBorrowedBuffer response_bytes); -SignalFfiError *signal_decrypt_message(SignalOwnedBuffer *out, SignalConstPointerSignalMessage message, SignalConstPointerProtocolAddress protocol_address, SignalConstPointerProtocolAddress local_address, SignalConstPointerFfiSessionStoreStruct session_store, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store); +SignalFfiError *signal_decrypt_message(SignalOwnedBuffer *out, SignalConstPointerSignalMessage message, SignalConstPointerProtocolAddress protocol_address, SignalConstPointerFfiSessionStoreStruct session_store, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store); SignalFfiError *signal_decrypt_pre_key_message(SignalOwnedBuffer *out, SignalConstPointerPreKeySignalMessage message, SignalConstPointerProtocolAddress protocol_address, SignalConstPointerProtocolAddress local_address, SignalConstPointerFfiSessionStoreStruct session_store, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store, SignalConstPointerFfiPreKeyStoreStruct prekey_store, SignalConstPointerFfiSignedPreKeyStoreStruct signed_prekey_store, SignalConstPointerFfiKyberPreKeyStoreStruct kyber_prekey_store); @@ -2121,7 +2118,9 @@ bool signal_init_logger(SignalLogLevel max_level, SignalFfiLoggerStruct logger); SignalFfiError *signal_key_transparency_aci_search_key(SignalOwnedBuffer *out, const SignalServiceIdFixedWidthBinaryBytes *aci); -SignalFfiError *signal_key_transparency_check(SignalCPromisePairOfOwnedBufferOfc_ucharOwnedBufferOfc_uchar *promise, SignalConstPointerTokioAsyncContext async_runtime, uint8_t environment, SignalConstPointerUnauthenticatedChatConnection chat_connection, const SignalServiceIdFixedWidthBinaryBytes *aci, SignalConstPointerPublicKey aci_identity_key, const char *e164, SignalOptionalBorrowedSliceOfc_uchar unidentified_access_key, SignalOptionalBorrowedSliceOfc_uchar username_hash, SignalOptionalBorrowedSliceOfc_uchar account_data, SignalOptionalBorrowedSliceOfc_uchar last_distinguished_tree_head, bool is_self_check, bool is_e164_discoverable); +SignalFfiError *signal_key_transparency_check(SignalCPromiseOwnedBufferOfc_uchar *promise, SignalConstPointerTokioAsyncContext async_runtime, uint8_t environment, SignalConstPointerUnauthenticatedChatConnection chat_connection, const SignalServiceIdFixedWidthBinaryBytes *aci, SignalConstPointerPublicKey aci_identity_key, const char *e164, SignalOptionalBorrowedSliceOfc_uchar unidentified_access_key, SignalOptionalBorrowedSliceOfc_uchar username_hash, SignalOptionalBorrowedSliceOfc_uchar account_data, SignalBorrowedBuffer last_distinguished_tree_head, bool is_self_check, bool is_e164_discoverable); + +SignalFfiError *signal_key_transparency_distinguished(SignalCPromiseOwnedBufferOfc_uchar *promise, SignalConstPointerTokioAsyncContext async_runtime, uint8_t environment, SignalConstPointerUnauthenticatedChatConnection chat_connection, SignalOptionalBorrowedSliceOfc_uchar last_distinguished_tree_head); SignalFfiError *signal_key_transparency_e164_search_key(SignalOwnedBuffer *out, const char *e164); @@ -2355,7 +2354,7 @@ SignalFfiError *signal_privatekey_serialize(SignalOwnedBuffer *out, SignalConstP SignalFfiError *signal_privatekey_sign(SignalOwnedBuffer *out, SignalConstPointerPrivateKey key, SignalBorrowedBuffer message); -SignalFfiError *signal_process_prekey_bundle(SignalConstPointerPreKeyBundle bundle, SignalConstPointerProtocolAddress protocol_address, SignalConstPointerProtocolAddress local_address, SignalConstPointerFfiSessionStoreStruct session_store, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store, uint64_t now); +SignalFfiError *signal_process_prekey_bundle(SignalConstPointerPreKeyBundle bundle, SignalConstPointerProtocolAddress protocol_address, SignalConstPointerFfiSessionStoreStruct session_store, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store, uint64_t now); SignalFfiError *signal_process_sender_key_distribution_message(SignalConstPointerProtocolAddress sender, SignalConstPointerSenderKeyDistributionMessage sender_key_distribution_message, SignalConstPointerFfiSenderKeyStoreStruct store); @@ -2783,8 +2782,6 @@ SignalFfiError *signal_unauthenticated_chat_connection_look_up_username_link(Sig SignalFfiError *signal_unauthenticated_chat_connection_send(SignalCPromiseFfiChatResponse *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthenticatedChatConnection chat, SignalConstPointerHttpRequest http_request, uint32_t timeout_millis); -SignalFfiError *signal_unauthenticated_chat_connection_send_message(SignalCPromisebool *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthenticatedChatConnection chat, const SignalServiceIdFixedWidthBinaryBytes *destination, uint64_t timestamp, SignalBorrowedSliceOfu32 device_ids, SignalBorrowedSliceOfu32 registration_ids, SignalBorrowedSliceOfBuffers contents, uint8_t auth_kind, SignalOptionalBorrowedSliceOfc_uchar auth_buffer, bool online_only, bool is_urgent); - SignalFfiError *signal_unauthenticated_chat_connection_send_multi_recipient_message(SignalCPromiseOwnedBufferOfServiceIdFixedWidthBinaryBytes *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthenticatedChatConnection chat, SignalBorrowedBuffer payload, uint64_t timestamp, SignalBorrowedBuffer auth, bool online_only, bool is_urgent); SignalFfiError *signal_unidentified_sender_message_content_deserialize(SignalMutPointerUnidentifiedSenderMessageContent *out, SignalBorrowedBuffer data); diff --git a/pkg/libsignalgo/message.go b/pkg/libsignalgo/message.go index 6cba873..1b581c0 100644 --- a/pkg/libsignalgo/message.go +++ b/pkg/libsignalgo/message.go @@ -49,7 +49,7 @@ func Encrypt(ctx context.Context, plaintext []byte, forAddress, localAddress *Ad return wrapCiphertextMessage(ciphertextMessage.raw), nil } -func Decrypt(ctx context.Context, message *Message, fromAddress, localAddress *Address, sessionStore SessionStore, identityStore IdentityKeyStore) ([]byte, error) { +func Decrypt(ctx context.Context, message *Message, fromAddress *Address, sessionStore SessionStore, identityStore IdentityKeyStore) ([]byte, error) { callbackCtx := NewCallbackContext(ctx) defer callbackCtx.Unref() var decrypted C.SignalOwnedBuffer = C.SignalOwnedBuffer{} @@ -57,7 +57,6 @@ func Decrypt(ctx context.Context, message *Message, fromAddress, localAddress *A &decrypted, message.constPtr(), fromAddress.constPtr(), - localAddress.constPtr(), callbackCtx.wrapSessionStore(sessionStore), callbackCtx.wrapIdentityKeyStore(identityStore), ) diff --git a/pkg/libsignalgo/prekeybundle.go b/pkg/libsignalgo/prekeybundle.go index 8a6fcaa..4cd5547 100644 --- a/pkg/libsignalgo/prekeybundle.go +++ b/pkg/libsignalgo/prekeybundle.go @@ -27,14 +27,13 @@ import ( "time" ) -func ProcessPreKeyBundle(ctx context.Context, bundle *PreKeyBundle, forAddress, localAddress *Address, sessionStore SessionStore, identityStore IdentityKeyStore) error { +func ProcessPreKeyBundle(ctx context.Context, bundle *PreKeyBundle, forAddress *Address, sessionStore SessionStore, identityStore IdentityKeyStore) error { callbackCtx := NewCallbackContext(ctx) defer callbackCtx.Unref() var now C.uint64_t = C.uint64_t(time.Now().Unix()) signalFfiError := C.signal_process_prekey_bundle( bundle.constPtr(), forAddress.constPtr(), - localAddress.constPtr(), callbackCtx.wrapSessionStore(sessionStore), callbackCtx.wrapIdentityKeyStore(identityStore), now, diff --git a/pkg/libsignalgo/prekeystore.go b/pkg/libsignalgo/prekeystore.go index 8c3c36f..ed8ea21 100644 --- a/pkg/libsignalgo/prekeystore.go +++ b/pkg/libsignalgo/prekeystore.go @@ -76,9 +76,9 @@ func signal_destroy_pre_key_store_callback(storeCtx unsafe.Pointer) { func (ctx *CallbackContext) wrapPreKeyStore(store PreKeyStore) C.SignalConstPointerFfiPreKeyStoreStruct { return C.SignalConstPointerFfiPreKeyStoreStruct{&C.SignalPreKeyStore{ ctx: wrapStore(ctx, store), - load_pre_key: C.SignalFfiPreKeyStoreLoadPreKey(C.signal_load_pre_key_callback), - store_pre_key: C.SignalFfiPreKeyStoreStorePreKey(C.signal_store_pre_key_callback), - remove_pre_key: C.SignalFfiPreKeyStoreRemovePreKey(C.signal_remove_pre_key_callback), - destroy: C.SignalFfiPreKeyStoreDestroy(C.signal_destroy_pre_key_store_callback), + load_pre_key: C.SignalFfiBridgePreKeyStoreLoadPreKey(C.signal_load_pre_key_callback), + store_pre_key: C.SignalFfiBridgePreKeyStoreStorePreKey(C.signal_store_pre_key_callback), + remove_pre_key: C.SignalFfiBridgePreKeyStoreRemovePreKey(C.signal_remove_pre_key_callback), + destroy: C.SignalFfiBridgePreKeyStoreDestroy(C.signal_destroy_pre_key_store_callback), }} } diff --git a/pkg/libsignalgo/senderkeystore.go b/pkg/libsignalgo/senderkeystore.go index 1649216..a07a287 100644 --- a/pkg/libsignalgo/senderkeystore.go +++ b/pkg/libsignalgo/senderkeystore.go @@ -70,8 +70,8 @@ func signal_destroy_sender_key_store_callback(storeCtx unsafe.Pointer) { func (ctx *CallbackContext) wrapSenderKeyStore(store SenderKeyStore) C.SignalConstPointerFfiSenderKeyStoreStruct { return C.SignalConstPointerFfiSenderKeyStoreStruct{&C.SignalSenderKeyStore{ ctx: wrapStore(ctx, store), - load_sender_key: C.SignalFfiSenderKeyStoreLoadSenderKey(C.signal_load_sender_key_callback), - store_sender_key: C.SignalFfiSenderKeyStoreStoreSenderKey(C.signal_store_sender_key_callback), - destroy: C.SignalFfiSenderKeyStoreDestroy(C.signal_destroy_sender_key_store_callback), + load_sender_key: C.SignalFfiBridgeSenderKeyStoreLoadSenderKey(C.signal_load_sender_key_callback), + store_sender_key: C.SignalFfiBridgeSenderKeyStoreStoreSenderKey(C.signal_store_sender_key_callback), + destroy: C.SignalFfiBridgeSenderKeyStoreDestroy(C.signal_destroy_sender_key_store_callback), }} } diff --git a/pkg/libsignalgo/session_test.go b/pkg/libsignalgo/session_test.go index dd05718..4bde894 100644 --- a/pkg/libsignalgo/session_test.go +++ b/pkg/libsignalgo/session_test.go @@ -30,7 +30,7 @@ import ( "go.mau.fi/mautrix-signal/pkg/libsignalgo" ) -func initializeSessions(t *testing.T, aliceStore, bobStore *InMemorySignalProtocolStore, bobAddress, aliceAddress *libsignalgo.Address) { +func initializeSessions(t *testing.T, aliceStore, bobStore *InMemorySignalProtocolStore, bobAddress *libsignalgo.Address) { ctx := context.TODO() bobPreKey, err := libsignalgo.GeneratePrivateKey() @@ -86,7 +86,7 @@ func initializeSessions(t *testing.T, aliceStore, bobStore *InMemorySignalProtoc assert.NoError(t, err) // Alice processes the bundle - err = libsignalgo.ProcessPreKeyBundle(ctx, bobBundle, bobAddress, aliceAddress, aliceStore, aliceStore) + err = libsignalgo.ProcessPreKeyBundle(ctx, bobBundle, bobAddress, aliceStore, aliceStore) assert.NoError(t, err) record, err := aliceStore.LoadSession(ctx, bobAddress) @@ -132,7 +132,7 @@ func TestSessionCipher(t *testing.T) { aliceStore := NewInMemorySignalProtocolStore() bobStore := NewInMemorySignalProtocolStore() - initializeSessions(t, aliceStore, bobStore, bobAddress, aliceAddress) + initializeSessions(t, aliceStore, bobStore, bobAddress) alicePlaintext := []byte{8, 6, 7, 5, 3, 0, 9} @@ -163,7 +163,7 @@ func TestSessionCipher(t *testing.T) { assert.NoError(t, err) aliceCiphertext2, err := libsignalgo.DeserializeMessage(bobCiphertext2Serialized) assert.NoError(t, err) - alicePlaintext2, err := libsignalgo.Decrypt(ctx, aliceCiphertext2, bobAddress, aliceAddress, aliceStore, aliceStore) + alicePlaintext2, err := libsignalgo.Decrypt(ctx, aliceCiphertext2, bobAddress, aliceStore, aliceStore) assert.NoError(t, err) assert.Equal(t, bobPlaintext2, alicePlaintext2) } @@ -183,7 +183,7 @@ func TestSessionCipherWithBadStore(t *testing.T) { aliceStore := NewInMemorySignalProtocolStore() bobStore := &BadInMemorySignalProtocolStore{NewInMemorySignalProtocolStore()} - initializeSessions(t, aliceStore, bobStore.InMemorySignalProtocolStore, bobAddress, aliceAddress) + initializeSessions(t, aliceStore, bobStore.InMemorySignalProtocolStore, bobAddress) alicePlaintext := []byte{8, 6, 7, 5, 3, 0, 9} @@ -216,7 +216,7 @@ func TestSealedSenderEncrypt_Repeated(t *testing.T) { aliceStore := NewInMemorySignalProtocolStore() bobStore := NewInMemorySignalProtocolStore() - initializeSessions(t, aliceStore, bobStore, bobAddress, aliceAddress) + initializeSessions(t, aliceStore, bobStore, bobAddress) trustRoot, err := libsignalgo.GenerateIdentityKeyPair() assert.NoError(t, err) @@ -252,18 +252,15 @@ func TestArchiveSession(t *testing.T) { ctx := context.TODO() setupLogging() - aliceACI := uuid.New() bobACI := uuid.New() - aliceAddress, err := libsignalgo.NewACIServiceID(aliceACI).Address(1) - assert.NoError(t, err) bobAddress, err := libsignalgo.NewACIServiceID(bobACI).Address(1) assert.NoError(t, err) aliceStore := NewInMemorySignalProtocolStore() bobStore := NewInMemorySignalProtocolStore() - initializeSessions(t, aliceStore, bobStore, bobAddress, aliceAddress) + initializeSessions(t, aliceStore, bobStore, bobAddress) session, err := aliceStore.LoadSession(ctx, bobAddress) assert.NoError(t, err) @@ -318,7 +315,7 @@ func TestSealedSenderGroupCipher(t *testing.T) { bobStore := NewInMemorySignalProtocolStore() - initializeSessions(t, aliceStore, bobStore, bobAddress, aliceAddress) + initializeSessions(t, aliceStore, bobStore, bobAddress) trustRoot, err := libsignalgo.GenerateIdentityKeyPair() assert.NoError(t, err) diff --git a/pkg/libsignalgo/sessionstore.go b/pkg/libsignalgo/sessionstore.go index 99000e5..2515232 100644 --- a/pkg/libsignalgo/sessionstore.go +++ b/pkg/libsignalgo/sessionstore.go @@ -67,8 +67,8 @@ func signal_destroy_session_store_callback(storeCtx unsafe.Pointer) { func (ctx *CallbackContext) wrapSessionStore(store SessionStore) C.SignalConstPointerFfiSessionStoreStruct { return C.SignalConstPointerFfiSessionStoreStruct{&C.SignalSessionStore{ ctx: wrapStore(ctx, store), - load_session: C.SignalFfiSessionStoreLoadSession(C.signal_load_session_callback), - store_session: C.SignalFfiSessionStoreStoreSession(C.signal_store_session_callback), - destroy: C.SignalFfiSessionStoreDestroy(C.signal_destroy_session_store_callback), + load_session: C.SignalFfiBridgeSessionStoreLoadSession(C.signal_load_session_callback), + store_session: C.SignalFfiBridgeSessionStoreStoreSession(C.signal_store_session_callback), + destroy: C.SignalFfiBridgeSessionStoreDestroy(C.signal_destroy_session_store_callback), }} } diff --git a/pkg/libsignalgo/signedprekeystore.go b/pkg/libsignalgo/signedprekeystore.go index b1306e2..cfb3015 100644 --- a/pkg/libsignalgo/signedprekeystore.go +++ b/pkg/libsignalgo/signedprekeystore.go @@ -67,8 +67,8 @@ func signal_destroy_signed_pre_key_store_callback(storeCtx unsafe.Pointer) { func (ctx *CallbackContext) wrapSignedPreKeyStore(store SignedPreKeyStore) C.SignalConstPointerFfiSignedPreKeyStoreStruct { return C.SignalConstPointerFfiSignedPreKeyStoreStruct{&C.SignalSignedPreKeyStore{ ctx: wrapStore(ctx, store), - load_signed_pre_key: C.SignalFfiSignedPreKeyStoreLoadSignedPreKey(C.signal_load_signed_pre_key_callback), - store_signed_pre_key: C.SignalFfiSignedPreKeyStoreStoreSignedPreKey(C.signal_store_signed_pre_key_callback), - destroy: C.SignalFfiSignedPreKeyStoreDestroy(C.signal_destroy_signed_pre_key_store_callback), + load_signed_pre_key: C.SignalFfiBridgeSignedPreKeyStoreLoadSignedPreKey(C.signal_load_signed_pre_key_callback), + store_signed_pre_key: C.SignalFfiBridgeSignedPreKeyStoreStoreSignedPreKey(C.signal_store_signed_pre_key_callback), + destroy: C.SignalFfiBridgeSignedPreKeyStoreDestroy(C.signal_destroy_signed_pre_key_store_callback), }} } diff --git a/pkg/libsignalgo/version.go b/pkg/libsignalgo/version.go index 1f7e94d..bd14084 100644 --- a/pkg/libsignalgo/version.go +++ b/pkg/libsignalgo/version.go @@ -2,4 +2,4 @@ package libsignalgo -const Version = "v0.93.2" +const Version = "v0.92.1" diff --git a/pkg/msgconv/from-matrix.go b/pkg/msgconv/from-matrix.go index a334afd..89b0181 100644 --- a/pkg/msgconv/from-matrix.go +++ b/pkg/msgconv/from-matrix.go @@ -110,24 +110,21 @@ func (mc *MessageConverter) ToSignal( return nil, fmt.Errorf("failed to convert sticker: %w", err) } att.Flags = proto.Uint32(uint32(signalpb.AttachmentPointer_BORDERLESS)) - - dm.Sticker = ParseStickerMeta(content.Info.BridgedSticker) - if dm.Sticker == nil { - var emoji *string - // TODO check for single grapheme cluster? - if len([]rune(content.Body)) == 1 { - emoji = proto.String(variationselector.Remove(content.Body)) - } - dm.Sticker = &signalpb.DataMessage_Sticker{ - // Signal iOS validates that pack id/key are of the correct length. - // Android is fine with any non-nil values (like a zero-length byte string). - PackId: make([]byte, 16), - PackKey: make([]byte, 32), - StickerId: proto.Uint32(0), - Emoji: emoji, - } + var emoji *string + // TODO check for single grapheme cluster? + if len([]rune(content.Body)) == 1 { + emoji = proto.String(variationselector.Remove(content.Body)) + } + dm.Sticker = &signalpb.DataMessage_Sticker{ + // Signal iOS validates that pack id/key are of the correct length. + // Android is fine with any non-nil values (like a zero-length byte string). + PackId: make([]byte, 16), + PackKey: make([]byte, 32), + StickerId: proto.Uint32(0), + + Data: att, + Emoji: emoji, } - dm.Sticker.Data = att case event.MsgLocation: lat, lon, err := parseGeoURI(content.GeoURI) if err != nil { diff --git a/pkg/msgconv/from-signal.go b/pkg/msgconv/from-signal.go index defbe44..96b4f10 100644 --- a/pkg/msgconv/from-signal.go +++ b/pkg/msgconv/from-signal.go @@ -468,16 +468,20 @@ func (mc *MessageConverter) convertStickerToMatrix(ctx context.Context, sticker converted.Content.Info.Height = 200 } converted.Content.Body = sticker.GetEmoji() - if len(sticker.GetPackId()) == PackIDLength && len(sticker.GetPackKey()) == PackKeyLength && !bytes.Equal(sticker.GetPackId(), zeroPackID) { - converted.Content.Info.BridgedSticker = &event.BridgedSticker{ - Network: StickerSourceID, - ID: strconv.FormatUint(uint64(sticker.GetStickerId()), 10), - Emoji: sticker.GetEmoji(), - PackURL: fmt.Sprintf(PackURLFormat, sticker.GetPackId(), sticker.GetPackKey()), - } - } converted.Type = event.EventSticker converted.Content.MsgType = "" + if converted.Extra == nil { + converted.Extra = map[string]any{} + } + // TODO fetch full pack metadata like the old bridge did? + converted.Extra["fi.mau.signal.sticker"] = map[string]any{ + "id": sticker.GetStickerId(), + "emoji": sticker.GetEmoji(), + "pack": map[string]any{ + "id": sticker.GetPackId(), + "key": sticker.GetPackKey(), + }, + } return converted } diff --git a/pkg/msgconv/imagepack.go b/pkg/msgconv/imagepack.go deleted file mode 100644 index a2529af..0000000 --- a/pkg/msgconv/imagepack.go +++ /dev/null @@ -1,199 +0,0 @@ -// mautrix-signal - A Matrix-Signal puppeting bridge. -// Copyright (C) 2026 Tulir Asokan -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package msgconv - -import ( - "bytes" - "context" - "encoding/hex" - "fmt" - "net/url" - "strconv" - "strings" - - "go.mau.fi/util/emojishortcodes" - "google.golang.org/protobuf/proto" - "maunium.net/go/mautrix" - "maunium.net/go/mautrix/bridgev2" - "maunium.net/go/mautrix/bridgev2/database" - "maunium.net/go/mautrix/event" - "maunium.net/go/mautrix/id" - - "go.mau.fi/mautrix-signal/pkg/signalid" - "go.mau.fi/mautrix-signal/pkg/signalmeow" - signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf" -) - -const StickerSourceID = "signal" -const PackURLFormat = "https://signal.art/addstickers/#pack_id=%x&pack_key=%x" - -const PackIDLength = 16 -const PackKeyLength = 32 -const PackURLLength = len(PackURLFormat) - len("%x")*2 + PackIDLength*2 + PackKeyLength*2 - -var zeroPackID = make([]byte, PackIDLength) - -func ParseStickerMeta(info *event.BridgedSticker) *signalpb.DataMessage_Sticker { - if info == nil || info.Network != StickerSourceID || len(info.PackURL) != PackURLLength { - return nil - } - stickerID, err := strconv.ParseUint(info.ID, 10, 32) - if err != nil { - return nil - } - packID, packKey, err := parsePackURL(info.PackURL) - if err != nil || len(packID) != PackIDLength || len(packKey) != PackKeyLength || bytes.Equal(packID, zeroPackID) { - return nil - } - return &signalpb.DataMessage_Sticker{ - PackId: packID, - PackKey: packKey, - StickerId: proto.Uint32(uint32(stickerID)), - Emoji: &info.Emoji, - } -} - -func parsePackURL(rawURL string) (packID, packKey []byte, err error) { - parsed, err := url.Parse(rawURL) - if err != nil { - return nil, nil, fmt.Errorf("invalid URL: %w", err) - } else if parsed.Host != "signal.art" || !strings.HasPrefix(parsed.Path, "/addstickers") { - return nil, nil, fmt.Errorf("invalid host or path in URL") - } - q, err := url.ParseQuery(parsed.Fragment) - if err != nil { - return nil, nil, fmt.Errorf("invalid URL fragment: %w", err) - } - packID, err = hex.DecodeString(q.Get("pack_id")) - if err != nil { - return nil, nil, fmt.Errorf("invalid pack ID in URL: %w", err) - } - packKey, err = hex.DecodeString(q.Get("pack_key")) - if err != nil { - return nil, nil, fmt.Errorf("invalid pack key in URL: %w", err) - } - return -} - -func (mc *MessageConverter) DownloadImagePack(ctx context.Context, url string) (*bridgev2.ImportedImagePack, error) { - packID, packKey, err := parsePackURL(url) - if err != nil { - return nil, bridgev2.WrapRespErr(err, mautrix.MNotFound) - } - manifest, err := signalmeow.DownloadStickerPackManifest(ctx, packID, packKey) - if err != nil { - return nil, fmt.Errorf("failed to download sticker pack manifest: %w", err) - } - topLevelExtra := map[string]any{ - "fi.mau.signal.stickerpack": map[string]any{ - "pack_id": hex.EncodeToString(packID), - "pack_key": hex.EncodeToString(packKey), - }, - } - content := &event.ImagePackEventContent{ - Images: make(map[string]*event.ImagePackImage, len(manifest.Stickers)), - Metadata: event.ImagePackMetadata{ - DisplayName: manifest.GetTitle(), - AvatarURL: "", - Usage: []event.ImagePackUsage{event.ImagePackUsageSticker}, - Attribution: manifest.GetAuthor(), - BridgedPack: &event.BridgedStickerPack{ - Network: StickerSourceID, - URL: fmt.Sprintf(PackURLFormat, packID, packKey), - }, - }, - } - imagesByID := make(map[uint32]id.ContentURIString, len(manifest.Stickers)) - uploadImage := func(sticker *signalpb.Pack_Sticker) (id.ContentURIString, error) { - stickerID := sticker.GetId() - existing, ok := imagesByID[stickerID] - if ok { - return existing, nil - } - var mxc id.ContentURIString - if mc.DirectMedia { - mediaID, err := signalid.DirectMediaSticker{ - PackID: packID, - PackKey: packKey, - StickerID: stickerID, - }.AsMediaID() - if err != nil { - return "", fmt.Errorf("failed to create media ID for sticker %d: %w", stickerID, err) - } - mxc, err = mc.Bridge.Matrix.GenerateContentURI(ctx, mediaID) - if err != nil { - return "", fmt.Errorf("failed to generate content URI for sticker %d: %w", stickerID, err) - } - } else { - dbKey := database.Key(fmt.Sprintf("stickercache:%x:%d", packID, stickerID)) - if cached := mc.Bridge.DB.KV.Get(ctx, dbKey); cached != "" { - mxc = id.ContentURIString(cached) - imagesByID[stickerID] = mxc - return mxc, nil - } - data, err := signalmeow.DownloadStickerPackItem(ctx, packID, packKey, stickerID) - if err != nil { - return "", fmt.Errorf("failed to download sticker %d: %w", stickerID, err) - } - mxc, _, err = mc.Bridge.Bot.UploadMedia(ctx, "", data, "", sticker.GetContentType()) - if err != nil { - return "", fmt.Errorf("failed to upload sticker %d: %w", stickerID, err) - } - mc.Bridge.DB.KV.Set(ctx, dbKey, string(mxc)) - } - imagesByID[stickerID] = mxc - return mxc, nil - } - for _, sticker := range manifest.Stickers { - mxc, err := uploadImage(sticker) - if err != nil { - return nil, err - } - shortcode := emojishortcodes.Get(sticker.GetEmoji()) - realShortcode := shortcode - i := 2 - for _, alreadyExists := content.Images[realShortcode]; alreadyExists; i++ { - realShortcode = fmt.Sprintf("%s_%d", shortcode, i) - } - content.Images[realShortcode] = &event.ImagePackImage{ - URL: mxc, - Body: sticker.GetEmoji(), - Info: &event.FileInfo{ - MimeType: sticker.GetContentType(), - Width: 200, - Height: 200, - BridgedSticker: &event.BridgedSticker{ - Network: StickerSourceID, - ID: strconv.FormatUint(uint64(sticker.GetId()), 10), - Emoji: sticker.GetEmoji(), - PackURL: content.Metadata.BridgedPack.URL, - }, - }, - } - } - if manifest.Cover != nil { - content.Metadata.AvatarURL, err = uploadImage(manifest.Cover) - if err != nil { - return nil, fmt.Errorf("failed to upload sticker pack cover: %w", err) - } - } - return &bridgev2.ImportedImagePack{ - Content: content, - Extra: topLevelExtra, - Shortcode: hex.EncodeToString(packID), - }, nil -} diff --git a/pkg/signalid/media.go b/pkg/signalid/media.go index a530c22..8c91b6a 100644 --- a/pkg/signalid/media.go +++ b/pkg/signalid/media.go @@ -34,7 +34,6 @@ const ( directMediaTypeGroupAvatar directMediaType = 1 directMediaTypeProfileAvatar directMediaType = 2 directMediaTypePlaintextDigestAttachment directMediaType = 3 - directMediaTypeSticker directMediaType = 4 ) type DirectMediaInfo interface { @@ -45,7 +44,6 @@ var ( _ DirectMediaInfo = (*DirectMediaAttachment)(nil) _ DirectMediaInfo = (*DirectMediaGroupAvatar)(nil) _ DirectMediaInfo = (*DirectMediaProfileAvatar)(nil) - _ DirectMediaInfo = (*DirectMediaSticker)(nil) ) type DirectMediaAttachment struct { @@ -129,30 +127,6 @@ func (m DirectMediaProfileAvatar) AsMediaID() (mediaID networkid.MediaID, err er return networkid.MediaID(buf.Bytes()), nil } -type DirectMediaSticker struct { - PackID []byte - PackKey []byte - StickerID uint32 -} - -const packIDLen = 16 -const packKeyLen = 32 -const directMediaStickerLen = 1 + packIDLen + packKeyLen + 4 - -func (m DirectMediaSticker) AsMediaID() (mediaID networkid.MediaID, err error) { - if len(m.PackID) != packIDLen { - return nil, fmt.Errorf("invalid pack ID length: %d", len(m.PackID)) - } else if len(m.PackKey) != packKeyLen { - return nil, fmt.Errorf("invalid pack key length: %d", len(m.PackKey)) - } - mediaID = make(networkid.MediaID, directMediaStickerLen) - mediaID[0] = byte(directMediaTypeSticker) - copy(mediaID[1:], m.PackID) - copy(mediaID[1+packIDLen:], m.PackKey) - binary.BigEndian.PutUint32(mediaID[1+packIDLen+packKeyLen:], m.StickerID) - return mediaID, nil -} - func ParseDirectMediaInfo(mediaID networkid.MediaID) (_ DirectMediaInfo, err error) { mediaIDLen := len(mediaID) if mediaIDLen == 0 { @@ -226,15 +200,6 @@ func ParseDirectMediaInfo(mediaID networkid.MediaID) (_ DirectMediaInfo, err err info.ProfileAvatarPath = string(profileAvatarPath) } return &info, nil - case directMediaTypeSticker: - var info DirectMediaSticker - if len(mediaID) != directMediaStickerLen { - return info, fmt.Errorf("invalid media ID length for sticker: %d", len(mediaID)) - } - info.PackID = mediaID[1 : 1+packIDLen] - info.PackKey = mediaID[1+packIDLen : 1+packIDLen+packKeyLen] - info.StickerID = binary.BigEndian.Uint32(mediaID[1+packIDLen+packKeyLen:]) - return &info, nil } return nil, fmt.Errorf("invalid direct media type %d", mediaType) diff --git a/pkg/signalmeow/attachments.go b/pkg/signalmeow/attachments.go index c091827..a48414e 100644 --- a/pkg/signalmeow/attachments.go +++ b/pkg/signalmeow/attachments.go @@ -35,7 +35,6 @@ import ( "github.com/rs/zerolog" "go.mau.fi/util/fallocate" - "go.mau.fi/util/pkcs7" "go.mau.fi/util/random" "google.golang.org/protobuf/proto" @@ -137,15 +136,6 @@ func DownloadAttachment( const MACLength = 32 const IVLength = 16 -func macAndAESDecrypt(body, key []byte) ([]byte, error) { - l := len(body) - MACLength - if !verifyMAC(key[MACLength:], body[:l], body[l:]) { - return nil, ErrInvalidMACForAttachment - } - - return aesDecrypt(key[:MACLength], body[:l]) -} - func decryptAttachment(body, key, digest []byte, plaintextDigest bool, size uint32) ([]byte, error) { if !plaintextDigest { hash := sha256.Sum256(body) @@ -153,7 +143,12 @@ func decryptAttachment(body, key, digest []byte, plaintextDigest bool, size uint return nil, ErrInvalidDigestForAttachment } } - decrypted, err := macAndAESDecrypt(body, key) + l := len(body) - MACLength + if !verifyMAC(key[MACLength:], body[:l], body[l:]) { + return nil, ErrInvalidMACForAttachment + } + + decrypted, err := aesDecrypt(key[:MACLength], body[:l]) if err != nil { return nil, err } @@ -245,14 +240,6 @@ func extend(data []byte, paddedLen int) []byte { } } -func macAndAESEncrypt(keys, plaintext []byte) ([]byte, error) { - encrypted, err := aesEncrypt(keys[:32], plaintext) - if err != nil { - return nil, err - } - return appendMAC(keys[32:], encrypted), nil -} - func (cli *Client) UploadAttachment(ctx context.Context, body []byte) (*signalpb.AttachmentPointer, error) { log := zerolog.Ctx(ctx).With().Str("func", "upload attachment").Logger() keys := random.Bytes(64) // combined AES and MAC keys @@ -268,10 +255,11 @@ func (cli *Client) UploadAttachment(ctx context.Context, body []byte) (*signalpb } body = extend(body, paddedLen) - encryptedWithMAC, err := macAndAESEncrypt(keys, body) + encrypted, err := aesEncrypt(keys[:32], body) if err != nil { return nil, err } + encryptedWithMAC := appendMAC(keys[32:], encrypted) // Get upload attributes from Signal server attributesPath := "/v4/attachments/form/upload" @@ -479,10 +467,13 @@ func aesDecrypt(key, ciphertext []byte) ([]byte, error) { } iv := ciphertext[:IVLength] - ciphertext = ciphertext[IVLength:] mode := cipher.NewCBCDecrypter(block, iv) mode.CryptBlocks(ciphertext, ciphertext) - return pkcs7.Unpad(ciphertext) + pad := ciphertext[len(ciphertext)-1] + if pad > aes.BlockSize { + return nil, fmt.Errorf("pad value (%d) larger than AES blocksize (%d)", pad, aes.BlockSize) + } + return ciphertext[aes.BlockSize : len(ciphertext)-int(pad)], nil } func aesDecryptFile(key []byte, file *os.File, downloadedSize int64) (int64, error) { @@ -542,11 +533,14 @@ func aesEncrypt(key, plaintext []byte) ([]byte, error) { return nil, err } - plaintext = pkcs7.Pad(plaintext, aes.BlockSize) + pad := aes.BlockSize - len(plaintext)%aes.BlockSize + plaintext = append(plaintext, bytes.Repeat([]byte{byte(pad)}, pad)...) + + ciphertext := make([]byte, len(plaintext)) iv := random.Bytes(16) mode := cipher.NewCBCEncrypter(block, iv) - mode.CryptBlocks(plaintext, plaintext) + mode.CryptBlocks(ciphertext, plaintext) - return append(iv, plaintext...), nil + return append(iv, ciphertext...), nil } diff --git a/pkg/signalmeow/keys.go b/pkg/signalmeow/keys.go index 5439755..f1801e5 100644 --- a/pkg/signalmeow/keys.go +++ b/pkg/signalmeow/keys.go @@ -413,10 +413,6 @@ func (cli *Client) FetchAndProcessPreKey(ctx context.Context, theirServiceID lib if cli.Store.RecipientStore.IsUnregistered(ctx, theirServiceID) { return fmt.Errorf("%w (cached)", ErrUnregisteredUser) } - localAddress, err := cli.Store.ACIServiceID().Address(uint(cli.Store.DeviceID)) - if err != nil { - return fmt.Errorf("failed to get own address: %w", err) - } // Fetch prekey deviceIDPath := "/*" if specificDeviceID >= 0 { @@ -522,7 +518,6 @@ func (cli *Client) FetchAndProcessPreKey(ctx context.Context, theirServiceID lib ctx, preKeyBundle, address, - localAddress, cli.Store.ACISessionStore, cli.Store.ACIIdentityStore, ) diff --git a/pkg/signalmeow/protobuf/ContactDiscovery.pb.go b/pkg/signalmeow/protobuf/ContactDiscovery.pb.go index 5cb232c..637a2d2 100644 --- a/pkg/signalmeow/protobuf/ContactDiscovery.pb.go +++ b/pkg/signalmeow/protobuf/ContactDiscovery.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.36.11 -// protoc v7.34.1 +// protoc v6.33.5 // source: ContactDiscovery.proto // Copyright 2021 Signal Messenger, LLC diff --git a/pkg/signalmeow/protobuf/DeviceName.pb.go b/pkg/signalmeow/protobuf/DeviceName.pb.go index 31b5704..5666b7e 100644 --- a/pkg/signalmeow/protobuf/DeviceName.pb.go +++ b/pkg/signalmeow/protobuf/DeviceName.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.36.11 -// protoc v7.34.1 +// protoc v6.33.5 // source: DeviceName.proto // Copyright 2018 Signal Messenger, LLC diff --git a/pkg/signalmeow/protobuf/Groups.pb.go b/pkg/signalmeow/protobuf/Groups.pb.go index 8d4e2e3..0c2b81b 100644 --- a/pkg/signalmeow/protobuf/Groups.pb.go +++ b/pkg/signalmeow/protobuf/Groups.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.36.11 -// protoc v7.34.1 +// protoc v6.33.5 // source: Groups.proto package signalpb diff --git a/pkg/signalmeow/protobuf/Provisioning.pb.go b/pkg/signalmeow/protobuf/Provisioning.pb.go index 88ebe90..c925fe6 100644 --- a/pkg/signalmeow/protobuf/Provisioning.pb.go +++ b/pkg/signalmeow/protobuf/Provisioning.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.36.11 -// protoc v7.34.1 +// protoc v6.33.5 // source: Provisioning.proto package signalpb diff --git a/pkg/signalmeow/protobuf/SignalService.pb.go b/pkg/signalmeow/protobuf/SignalService.pb.go index c4268dd..32842bf 100644 --- a/pkg/signalmeow/protobuf/SignalService.pb.go +++ b/pkg/signalmeow/protobuf/SignalService.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.36.11 -// protoc v7.34.1 +// protoc v6.33.5 // source: SignalService.proto package signalpb diff --git a/pkg/signalmeow/protobuf/StickerResources.pb.go b/pkg/signalmeow/protobuf/StickerResources.pb.go index f8194aa..e83cda1 100644 --- a/pkg/signalmeow/protobuf/StickerResources.pb.go +++ b/pkg/signalmeow/protobuf/StickerResources.pb.go @@ -6,7 +6,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.36.11 -// protoc v7.34.1 +// protoc v6.33.5 // source: StickerResources.proto package signalpb diff --git a/pkg/signalmeow/protobuf/StorageService.pb.go b/pkg/signalmeow/protobuf/StorageService.pb.go index bbe88ef..619221f 100644 --- a/pkg/signalmeow/protobuf/StorageService.pb.go +++ b/pkg/signalmeow/protobuf/StorageService.pb.go @@ -6,7 +6,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.36.11 -// protoc v7.34.1 +// protoc v6.33.5 // source: StorageService.proto package signalpb @@ -1401,7 +1401,6 @@ type GroupV2Record struct { HideStory bool `protobuf:"varint,8,opt,name=hideStory,proto3" json:"hideStory,omitempty"` StorySendMode GroupV2Record_StorySendMode `protobuf:"varint,10,opt,name=storySendMode,proto3,enum=signalservice.GroupV2Record_StorySendMode" json:"storySendMode,omitempty"` AvatarColor *AvatarColor `protobuf:"varint,11,opt,name=avatarColor,proto3,enum=signalservice.AvatarColor,oneof" json:"avatarColor,omitempty"` - VerifiedNameHash []byte `protobuf:"bytes,12,opt,name=verifiedNameHash,proto3" json:"verifiedNameHash,omitempty"` // SHA-256 of UTF-8 encoded decrypted group title that was last verified unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -1506,13 +1505,6 @@ func (x *GroupV2Record) GetAvatarColor() AvatarColor { return AvatarColor_A100 } -func (x *GroupV2Record) GetVerifiedNameHash() []byte { - if x != nil { - return x.VerifiedNameHash - } - return nil -} - type Payments struct { state protoimpl.MessageState `protogen:"open.v1"` Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"` @@ -3203,7 +3195,7 @@ const file_StorageService_proto_rawDesc = "" + "\vwhitelisted\x18\x03 \x01(\bR\vwhitelisted\x12\x1a\n" + "\barchived\x18\x04 \x01(\bR\barchived\x12\"\n" + "\fmarkedUnread\x18\x05 \x01(\bR\fmarkedUnread\x120\n" + - "\x13mutedUntilTimestamp\x18\x06 \x01(\x04R\x13mutedUntilTimestamp\"\xcd\x04\n" + + "\x13mutedUntilTimestamp\x18\x06 \x01(\x04R\x13mutedUntilTimestamp\"\xa1\x04\n" + "\rGroupV2Record\x12\x1c\n" + "\tmasterKey\x18\x01 \x01(\fR\tmasterKey\x12\x18\n" + "\ablocked\x18\x02 \x01(\bR\ablocked\x12 \n" + @@ -3215,8 +3207,7 @@ const file_StorageService_proto_rawDesc = "" + "\thideStory\x18\b \x01(\bR\thideStory\x12P\n" + "\rstorySendMode\x18\n" + " \x01(\x0e2*.signalservice.GroupV2Record.StorySendModeR\rstorySendMode\x12A\n" + - "\vavatarColor\x18\v \x01(\x0e2\x1a.signalservice.AvatarColorH\x00R\vavatarColor\x88\x01\x01\x12*\n" + - "\x10verifiedNameHash\x18\f \x01(\fR\x10verifiedNameHash\"7\n" + + "\vavatarColor\x18\v \x01(\x0e2\x1a.signalservice.AvatarColorH\x00R\vavatarColor\x88\x01\x01\"7\n" + "\rStorySendMode\x12\v\n" + "\aDEFAULT\x10\x00\x12\f\n" + "\bDISABLED\x10\x01\x12\v\n" + diff --git a/pkg/signalmeow/protobuf/StorageService.proto b/pkg/signalmeow/protobuf/StorageService.proto index dd232ca..d22babc 100644 --- a/pkg/signalmeow/protobuf/StorageService.proto +++ b/pkg/signalmeow/protobuf/StorageService.proto @@ -172,7 +172,6 @@ message GroupV2Record { reserved /* storySendEnabled */ 9; StorySendMode storySendMode = 10; optional AvatarColor avatarColor = 11; - bytes verifiedNameHash = 12; // SHA-256 of UTF-8 encoded decrypted group title that was last verified } message Payments { diff --git a/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.go b/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.go index 5979a4c..e30f6d6 100644 --- a/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.go +++ b/pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.36.11 -// protoc v7.34.1 +// protoc v6.33.5 // source: UnidentifiedDelivery.proto // Copyright 2018 Signal Messenger, LLC diff --git a/pkg/signalmeow/protobuf/WebSocketResources.pb.go b/pkg/signalmeow/protobuf/WebSocketResources.pb.go index 66520eb..f35110d 100644 --- a/pkg/signalmeow/protobuf/WebSocketResources.pb.go +++ b/pkg/signalmeow/protobuf/WebSocketResources.pb.go @@ -6,7 +6,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.36.11 -// protoc v7.34.1 +// protoc v6.33.5 // source: WebSocketResources.proto package signalpb diff --git a/pkg/signalmeow/protobuf/backuppb/Backup.pb.go b/pkg/signalmeow/protobuf/backuppb/Backup.pb.go index bc488e7..326c170 100644 --- a/pkg/signalmeow/protobuf/backuppb/Backup.pb.go +++ b/pkg/signalmeow/protobuf/backuppb/Backup.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.36.11 -// protoc v7.34.1 +// protoc v6.33.5 // source: backuppb/Backup.proto package backuppb diff --git a/pkg/signalmeow/protobuf/update-protos.sh b/pkg/signalmeow/protobuf/update-protos.sh index f9c86fc..ffaa697 100755 --- a/pkg/signalmeow/protobuf/update-protos.sh +++ b/pkg/signalmeow/protobuf/update-protos.sh @@ -1,8 +1,8 @@ #!/bin/bash set -euo pipefail -ANDROID_GIT_REVISION=${1:-439760e7732585bfd078d92d93732c04cc31e29e} -DESKTOP_GIT_REVISION=${1:-1b2a3e7b283c32c5654a39da12fc04139fd26dbd} +ANDROID_GIT_REVISION=${1:-dfd2f7baf96825834f784900ce644e9ead8a9a89} +DESKTOP_GIT_REVISION=${1:-60a1e125452ee672d8747564d0055d5bfec9f679} update_proto() { case "$1" in diff --git a/pkg/signalmeow/receiving_decrypt.go b/pkg/signalmeow/receiving_decrypt.go index 1d2c8cc..6296f00 100644 --- a/pkg/signalmeow/receiving_decrypt.go +++ b/pkg/signalmeow/receiving_decrypt.go @@ -243,16 +243,11 @@ func (cli *Client) decryptCiphertextEnvelope( if identityStore == nil { return nil, fmt.Errorf("no identity store for destination service ID %s", destinationServiceID) } - destinationAddress, err := destinationServiceID.Address(uint(cli.Store.DeviceID)) - if err != nil { - return nil, fmt.Errorf("failed to get own address: %w", err) - } plaintext, ciphertextHash, err := cli.bufferedDecryptTxn(ctx, ciphertext, serverTimestamp, func(ctx context.Context) ([]byte, error) { return libsignalgo.Decrypt( ctx, message, senderAddress, - destinationAddress, sessionStore, identityStore, ) diff --git a/pkg/signalmeow/sending.go b/pkg/signalmeow/sending.go index a485b54..769798a 100644 --- a/pkg/signalmeow/sending.go +++ b/pkg/signalmeow/sending.go @@ -384,7 +384,15 @@ func syncMessageFromSoloEditMessage(editMessage *signalpb.EditMessage, result Su } func syncMessageFromReadReceiptMessage(ctx context.Context, receiptMessage *signalpb.ReceiptMessage, messageSender libsignalgo.ServiceID) *signalpb.Content { - if *receiptMessage.Type != signalpb.ReceiptMessage_READ || messageSender.Type != libsignalgo.ServiceIDTypeACI { + if *receiptMessage.Type != signalpb.ReceiptMessage_READ { + zerolog.Ctx(ctx).Warn(). + Any("receipt_message_type", receiptMessage.Type). + Msg("syncMessageFromReadReceiptMessage called with non-read receipt message") + return nil + } else if messageSender.Type != libsignalgo.ServiceIDTypeACI { + zerolog.Ctx(ctx).Warn(). + Stringer("message_sender", messageSender). + Msg("syncMessageFromReadReceiptMessage called with non-ACI message sender") return nil } read := []*signalpb.SyncMessage_Read{} diff --git a/pkg/signalmeow/sticker.go b/pkg/signalmeow/sticker.go deleted file mode 100644 index 2759d18..0000000 --- a/pkg/signalmeow/sticker.go +++ /dev/null @@ -1,251 +0,0 @@ -// mautrix-signal - A Matrix-signal puppeting bridge. -// Copyright (C) 2026 Tulir Asokan -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -package signalmeow - -import ( - "bytes" - "context" - "crypto/hkdf" - "crypto/sha256" - "encoding/hex" - "errors" - "fmt" - "io" - "mime/multipart" - "net/http" - "net/textproto" - "sync" - - "go.mau.fi/util/exerrors" - "go.mau.fi/util/random" - "golang.org/x/sync/semaphore" - "google.golang.org/protobuf/proto" - - signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf" - "go.mau.fi/mautrix-signal/pkg/signalmeow/web" -) - -func DownloadStickerPackManifest(ctx context.Context, packID, packKey []byte) (*signalpb.Pack, error) { - if len(packID) != 16 { - return nil, fmt.Errorf("invalid pack ID length: %d", len(packID)) - } - resp, err := downloadStickerData(ctx, fmt.Sprintf("/stickers/%x/manifest.proto", packID), packKey) - if err != nil { - return nil, err - } - var pack signalpb.Pack - err = proto.Unmarshal(resp, &pack) - if err != nil { - return nil, fmt.Errorf("failed to unmarshal decrypted manifest: %w", err) - } - return &pack, nil -} - -func DownloadStickerPackItem(ctx context.Context, packID, packKey []byte, stickerID uint32) ([]byte, error) { - if len(packID) != 16 { - return nil, fmt.Errorf("invalid pack ID length: %d", len(packID)) - } - return downloadStickerData(ctx, fmt.Sprintf("/stickers/%x/full/%d", packID, stickerID), packKey) -} - -func downloadStickerData(ctx context.Context, path string, packKey []byte) ([]byte, error) { - if len(packKey) != 32 { - return nil, fmt.Errorf("invalid pack key length: %d", len(packKey)) - } - var body, decrypted []byte - resp, err := web.SendHTTPRequest(ctx, web.CDN1Hostname, http.MethodGet, path, nil) - defer web.CloseBody(resp) - if err != nil { - return nil, fmt.Errorf("failed to make request: %w", err) - } else if resp.StatusCode != http.StatusOK { - return nil, fmt.Errorf("unexpected status code %d", resp.StatusCode) - } else if body, err = io.ReadAll(resp.Body); err != nil { - return nil, fmt.Errorf("failed to read response: %w", err) - } else if decrypted, err = decryptSticker(packKey, body); err != nil { - return nil, fmt.Errorf("failed to decrypt response: %w", err) - } else { - return decrypted, nil - } -} - -type stickerUploadAttributes struct { - ACL string `json:"acl"` - Algorithm string `json:"algorithm"` - Credential string `json:"credential"` - Date string `json:"date"` - ID int `json:"id"` - Key string `json:"key"` - Policy string `json:"policy"` - Signature string `json:"signature"` -} - -func (sua *stickerUploadAttributes) makeFormBody(encryptedData []byte) (*web.HTTPReqOpt, error) { - var buf bytes.Buffer - writer := multipart.NewWriter(&buf) - var closed bool - // This isn't necessary in practice, just do it to avoid linter warnings - defer func() { - if !closed { - _ = writer.Close() - } - }() - fields := map[string]string{ - "key": sua.Key, - "acl": sua.ACL, - "policy": sua.Policy, - "x-amz-algorithm": sua.Algorithm, - "x-amz-credential": sua.Credential, - "x-amz-date": sua.Date, - "Content-Type": "application/octet-stream", - } - for key, value := range fields { - err := writer.WriteField(key, value) - if err != nil { - return nil, fmt.Errorf("failed to write multipart field %s: %w", key, err) - } - } - filePart, err := writer.CreatePart(textproto.MIMEHeader{ - "Content-Type": []string{"application/octet-stream"}, - "Content-Disposition": []string{`form-data; name="file"`}, - }) - if err != nil { - return nil, fmt.Errorf("failed to create multipart file part: %w", err) - } - _, err = filePart.Write(encryptedData) - if err != nil { - return nil, fmt.Errorf("failed to write file data to multipart body: %w", err) - } - err = writer.Close() - if err != nil { - return nil, fmt.Errorf("failed to close multipart writer: %w", err) - } - closed = true - return &web.HTTPReqOpt{ - Body: buf.Bytes(), - ContentType: web.ContentType(writer.FormDataContentType()), - }, nil -} - -func (sua *stickerUploadAttributes) upload(ctx context.Context, packKey, fileData []byte) error { - encryptedData, err := macAndAESEncrypt(fileData, deriveStickerPackKey(packKey)) - if err != nil { - return fmt.Errorf("failed to encrypt sticker data: %w", err) - } - req, err := sua.makeFormBody(encryptedData) - if err != nil { - return fmt.Errorf("failed to prepare request: %w", err) - } - resp, err := web.SendHTTPRequest(ctx, web.CDN1Hostname, http.MethodPost, "/", req) - if err != nil { - return err - } - _ = resp.Body.Close() - if resp.StatusCode < 200 || resp.StatusCode >= 300 { - return fmt.Errorf("unexpected status code %d", resp.StatusCode) - } - return nil -} - -func (sua *stickerUploadAttributes) uploadAsync( - ctx context.Context, - packKey []byte, - getFileData func(context.Context) ([]byte, error), - sema *semaphore.Weighted, - done func(), - onError func(error), -) { - defer done() - err := sema.Acquire(ctx, 1) - if err != nil { - return - } - defer sema.Release(1) - fileData, err := getFileData(ctx) - if err == nil { - err = sua.upload(ctx, packKey, fileData) - } - if err != nil { - onError(err) - } -} - -type stickerPackUploadAttributes struct { - PackID string `json:"packId"` - Manifest *stickerUploadAttributes `json:"manifest"` - Stickers []*stickerUploadAttributes `json:"stickers"` -} - -var StickerUploadParallelism = 4 - -func (cli *Client) UploadStickerPack(ctx context.Context, pack *signalpb.Pack, stickerData []func(context.Context) ([]byte, error)) (packID, packKey []byte, err error) { - for i, sticker := range pack.Stickers { - if sticker.GetId() >= uint32(len(stickerData)) { - return nil, nil, fmt.Errorf("sticker ID %d at index %d is out of bounds, only %d sticker blobs provided", sticker.GetId(), i, len(stickerData)) - } - } - marshaledPack, err := proto.Marshal(pack) - if err != nil { - return nil, nil, fmt.Errorf("failed to marshal pack: %w", err) - } - packKey = random.Bytes(32) - resp, err := cli.AuthedWS.SendRequest(ctx, http.MethodGet, fmt.Sprintf("/v1/sticker/pack/form/%d", len(stickerData)), nil, nil) - if err != nil { - return nil, nil, fmt.Errorf("failed to get upload form: %w", err) - } - var packAttributes stickerPackUploadAttributes - err = web.DecodeWSResponseBody(ctx, &packAttributes, resp) - if err != nil { - return nil, nil, fmt.Errorf("failed to decode pack attributes: %w", err) - } - if len(packAttributes.Stickers) != len(stickerData) { - return nil, nil, fmt.Errorf("expected %d sticker upload attribute sets, got %d", len(stickerData), len(packAttributes.Stickers)) - } - packID, err = hex.DecodeString(packAttributes.PackID) - if err != nil { - return nil, nil, fmt.Errorf("invalid pack ID in response: %w", err) - } - err = packAttributes.Manifest.upload(ctx, packKey, marshaledPack) - if err != nil { - return nil, nil, fmt.Errorf("failed to upload manifest: %w", err) - } - var wg sync.WaitGroup - wg.Add(len(packAttributes.Stickers)) - sema := semaphore.NewWeighted(int64(StickerUploadParallelism)) - var errorList []error - var errorLock sync.Mutex - for i, attrs := range packAttributes.Stickers { - go attrs.uploadAsync(ctx, packKey, stickerData[i], sema, wg.Done, func(err error) { - errorLock.Lock() - errorList = append(errorList, fmt.Errorf("failed to upload sticker #%d: %w", i+1, err)) - errorLock.Unlock() - }) - } - wg.Wait() - err = ctx.Err() - if err == nil { - err = errors.Join(errorList...) - } - return -} - -func decryptSticker(packKey, ciphertext []byte) ([]byte, error) { - return macAndAESDecrypt(ciphertext, deriveStickerPackKey(packKey)) -} - -func deriveStickerPackKey(key []byte) []byte { - return exerrors.Must(hkdf.Key(sha256.New, key, make([]byte, 32), "Sticker Pack", 2*32)) -} diff --git a/pkg/signalmeow/web/web.go b/pkg/signalmeow/web/web.go index f211b77..d0fcd01 100644 --- a/pkg/signalmeow/web/web.go +++ b/pkg/signalmeow/web/web.go @@ -28,7 +28,6 @@ import ( "net/http" "runtime" "strings" - "time" "github.com/rs/zerolog" @@ -130,7 +129,6 @@ func SendHTTPRequest(ctx context.Context, host, method, path string, opt *HTTPRe } else { req.Header.Set("Content-Type", string(ContentTypeJSON)) } - req.ContentLength = int64(len(opt.Body)) req.Header.Set("Content-Length", fmt.Sprintf("%d", len(opt.Body))) req.Header.Set("User-Agent", UserAgent) req.Header.Set("X-Signal-Agent", SignalAgent) @@ -141,14 +139,12 @@ func SendHTTPRequest(ctx context.Context, host, method, path string, opt *HTTPRe httpReqCounter++ log = log.With().Int("request_number", httpReqCounter).Logger() log.Trace().Msg("Sending HTTP request") - start := time.Now() resp, err := SignalHTTPClient.Do(req) - dur := time.Since(start) if err != nil { - log.Err(err).Dur("duration", dur).Msg("Error sending request") + log.Err(err).Msg("Error sending request") return nil, err } - log.Debug().Int("status_code", resp.StatusCode).Dur("duration", dur).Msg("Received HTTP response") + log.Debug().Int("status_code", resp.StatusCode).Msg("received HTTP response") return resp, nil }