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
}