1
0
Fork 0
mirror of https://github.com/mautrix/signal.git synced 2026-05-14 21:26:54 -04:00

Compare commits

..

No commits in common. "main" and "v0.2604.0" have entirely different histories.

40 changed files with 239 additions and 767 deletions

View file

@ -11,8 +11,7 @@ type: Bug
### Checklist ### Checklist
<!-- All items below are mandatory. Issues not following the rules may be closed without comment. --> <!-- Both items below are mandatory. Issues not following the rules may be closed without comment. -->
* [ ] 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). * [ ] 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. * [ ] 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: ``

10
go.mod
View file

@ -11,17 +11,16 @@ require (
github.com/emersion/go-vcard v0.0.0-20241024213814-c9703dde27ff github.com/emersion/go-vcard v0.0.0-20241024213814-c9703dde27ff
github.com/google/uuid v1.6.0 github.com/google/uuid v1.6.0
github.com/mattn/go-pointer v0.0.1 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/stretchr/testify v1.11.1
github.com/tidwall/gjson v1.18.0 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/crypto v0.50.0
golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f
golang.org/x/net v0.53.0 golang.org/x/net v0.53.0
golang.org/x/sync v0.20.0
google.golang.org/protobuf v1.36.11 google.golang.org/protobuf v1.36.11
gopkg.in/yaml.v3 v3.0.1 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 ( require (
@ -32,7 +31,7 @@ require (
github.com/lib/pq v1.12.3 // indirect github.com/lib/pq v1.12.3 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // 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/petermattis/goid v0.0.0-20260330135022-df67b199bc81 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect
@ -44,6 +43,7 @@ require (
github.com/yuin/goldmark v1.8.2 // indirect github.com/yuin/goldmark v1.8.2 // indirect
go.mau.fi/zeroconfig v0.2.0 // indirect go.mau.fi/zeroconfig v0.2.0 // indirect
golang.org/x/mod v0.35.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/sys v0.43.0 // indirect
golang.org/x/text v0.36.0 // indirect golang.org/x/text v0.36.0 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect

16
go.sum
View file

@ -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-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 h1:n+XhsuGeVO6MEAp7xyEukFINEa+Quek5psIR/ylA6o0=
github.com/mattn/go-pointer v0.0.1/go.mod h1:2zXcozF6qYGgmsG+SeTZz3oAbFLdD3OWqnUbNvJZAlc= 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.42 h1:MigqEP4ZmHw3aIdIT7T+9TLa90Z6smwcthx+Azv4Cgo=
github.com/mattn/go-sqlite3 v1.14.44/go.mod h1:pjEuOr8IwzLJP2MfGeTb0A35jauH+C2kbHKBr7yXKVQ= 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 h1:WDsQxOJDy0N1VRAjXLpi8sCEZRSGarLWQevDxpTBRrM=
github.com/petermattis/goid v0.0.0-20260330135022-df67b199bc81/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= 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= 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/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 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU=
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= 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.0 h1:VD0ykx7HMiMJytqINBsKcbLS+BJ4WYjz+05us+LRTdI=
github.com/rs/zerolog v1.35.1/go.mod h1:EjML9kdfa/RMA7h/6z6pYmq1ykOuA8/mjWaEvGI+jcw= 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 h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M= 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= 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/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 h1:kEGpgqJXdgbkhcOgBxkC0X0PmoPG1ZyoZ117rDVp4zE=
github.com/yuin/goldmark v1.8.2/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= 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.8 h1:+/jf8eM2dAT2wx9UidmaneH28r/CSCKCniCyby1qWz8=
go.mau.fi/util v0.9.9-0.20260511124621-9241e81bdf25/go.mod h1:jE9FfhbgEgAwxei6lomO9v8zdCIATcquONUu4vjRwSs= 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 h1:e/OGEERqVRRKlgaro7E6bh8xXiKFSXB3eNNIud7FUjU=
go.mau.fi/zeroconfig v0.2.0/go.mod h1:J0Vn0prHNOm493oZoQ84kq83ZaNCYZnq+noI1b1eN8w= go.mau.fi/zeroconfig v0.2.0/go.mod h1:J0Vn0prHNOm493oZoQ84kq83ZaNCYZnq+noI1b1eN8w=
golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI= 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= 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 h1:YiaRc0tEI3toYtJMRIfjP+jklH45uDHtT80nUamyD4M=
maunium.net/go/mauflag v1.0.0/go.mod h1:nLivPOpTpHnpzEh8jEdSL9UqO9+/KBJFmNRlwKfkPeA= 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.0 h1:yfEYwoIluVWkofUgbZl9gP4i5nQTF+QNsxtb+r5bKlM=
maunium.net/go/mautrix v0.27.1-0.20260513120123-5fba7e3afae4/go.mod h1:3sOGhXi3P1V6/NruTA0gujkvTypXVUraWktCuTGyDuM= maunium.net/go/mautrix v0.27.0/go.mod h1:7QpEQiTy6p4LHkXXaZI+N46tGYy8HMhD0JjzZAFoFWs=

View file

@ -38,7 +38,7 @@ func supportedIfFFmpeg() event.CapabilitySupportLevel {
} }
func capID() string { func capID() string {
base := "fi.mau.signal.capabilities.2026_05_12" base := "fi.mau.signal.capabilities.2025_12_09"
if ffmpeg.Supported() { if ffmpeg.Supported() {
return base + "+ffmpeg" return base + "+ffmpeg"
} }
@ -111,8 +111,7 @@ var signalCaps = &event.RoomFeatures{
}, },
event.CapMsgSticker: { event.CapMsgSticker: {
MimeTypes: map[string]event.CapabilitySupportLevel{ MimeTypes: map[string]event.CapabilitySupportLevel{
// Signal clients will only render static webp, so apng is preferred "image/webp": event.CapLevelFullySupported,
"image/webp": event.CapLevelPartialSupport,
"image/png": event.CapLevelFullySupported, "image/png": event.CapLevelFullySupported,
"image/apng": event.CapLevelFullySupported, "image/apng": event.CapLevelFullySupported,
"image/gif": supportedIfFFmpeg(), "image/gif": supportedIfFFmpeg(),
@ -212,7 +211,6 @@ var signalGeneralCaps = &bridgev2.NetworkGeneralCapabilities{
AggressiveUpdateInfo: true, AggressiveUpdateInfo: true,
ImplicitReadReceipts: true, ImplicitReadReceipts: true,
Provisioning: bridgev2.ProvisioningCapabilities{ Provisioning: bridgev2.ProvisioningCapabilities{
ImagePackImport: true,
ResolveIdentifier: bridgev2.ResolveIdentifierCapabilities{ ResolveIdentifier: bridgev2.ResolveIdentifierCapabilities{
CreateDM: true, CreateDM: true,
LookupPhone: true, LookupPhone: true,
@ -237,5 +235,5 @@ func (s *SignalConnector) GetCapabilities() *bridgev2.NetworkGeneralCapabilities
} }
func (s *SignalConnector) GetBridgeInfoVersion() (info, capabilities int) { func (s *SignalConnector) GetBridgeInfoVersion() (info, capabilities int) {
return 1, 8 return 1, 7
} }

View file

@ -27,7 +27,6 @@ import (
"maunium.net/go/mautrix/bridgev2" "maunium.net/go/mautrix/bridgev2"
"maunium.net/go/mautrix/bridgev2/networkid" "maunium.net/go/mautrix/bridgev2/networkid"
"maunium.net/go/mautrix/bridgev2/status" "maunium.net/go/mautrix/bridgev2/status"
"maunium.net/go/mautrix/event"
"go.mau.fi/mautrix-signal/pkg/signalid" "go.mau.fi/mautrix-signal/pkg/signalid"
"go.mau.fi/mautrix-signal/pkg/signalmeow" "go.mau.fi/mautrix-signal/pkg/signalmeow"
@ -47,7 +46,6 @@ type SignalClient struct {
var ( var (
_ bridgev2.NetworkAPI = (*SignalClient)(nil) _ bridgev2.NetworkAPI = (*SignalClient)(nil)
_ bridgev2.BackgroundSyncingNetworkAPI = (*SignalClient)(nil) _ bridgev2.BackgroundSyncingNetworkAPI = (*SignalClient)(nil)
_ bridgev2.StickerImportingNetworkAPI = (*SignalClient)(nil)
) )
var pushCfg = &bridgev2.PushConfig{ 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) { func (s *SignalClient) LogoutRemote(ctx context.Context) {
if s.Client == nil { if s.Client == nil {
return return

View file

@ -4,6 +4,7 @@ import (
"context" "context"
"encoding/base64" "encoding/base64"
"fmt" "fmt"
"io"
"os" "os"
"maunium.net/go/mautrix/bridgev2" "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) return nil, fmt.Errorf("failed to parse direct media id: %w", err)
} }
var rawDataResp []byte
switch info := info.(type) { switch info := info.(type) {
case *signalid.DirectMediaAttachment: case *signalid.DirectMediaAttachment:
log.Info(). 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) return nil, fmt.Errorf("failed to to get group master key: %w", err)
} }
rawDataResp, err = client.Client.DownloadGroupAvatar(ctx, info.GroupAvatarPath, groupMasterKey) return &mediaproxy.GetMediaResponseCallback{
Callback: func(w io.Writer) (int64, error) {
data, err := client.Client.DownloadGroupAvatar(ctx, info.GroupAvatarPath, groupMasterKey)
if err != nil { if err != nil {
log.Err(err).Msg("Direct download failed") log.Err(err).Msg("Direct download failed")
return nil, err return 0, err
} }
_, err = w.Write(data)
return int64(len(data)), err
},
}, nil
case *signalid.DirectMediaProfileAvatar: case *signalid.DirectMediaProfileAvatar:
log.Info(). log.Info().
Stringer("user_id", info.UserID). 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") return nil, fmt.Errorf("profile key not found")
} }
rawDataResp, err = client.Client.DownloadUserAvatar(ctx, info.ProfileAvatarPath, *profileKey) return &mediaproxy.GetMediaResponseCallback{
Callback: func(w io.Writer) (int64, error) {
data, err := client.Client.DownloadUserAvatar(ctx, info.ProfileAvatarPath, *profileKey)
if err != nil { if err != nil {
log.Err(err).Msg("Direct download failed") log.Err(err).Msg("Direct download failed")
return nil, err return 0, err
} }
case *signalid.DirectMediaSticker:
log.Info().
Hex("pack_id", info.PackID).
Uint32("sticker_id", info.StickerID).
Msg("Direct downloading sticker")
rawDataResp, err = signalmeow.DownloadStickerPackItem(ctx, info.PackID, info.PackKey, info.StickerID) _, err = w.Write(data)
if err != nil { return int64(len(data)), err
log.Err(err).Msg("Direct download failed") },
return nil, err }, nil
}
default: default:
return nil, fmt.Errorf("no downloader for direct media type: %T", info) 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
} }

View file

@ -159,11 +159,11 @@ func signal_destroy_identity_key_store_callback(storeCtx unsafe.Pointer) {
func (ctx *CallbackContext) wrapIdentityKeyStore(store IdentityKeyStore) C.SignalConstPointerFfiIdentityKeyStoreStruct { func (ctx *CallbackContext) wrapIdentityKeyStore(store IdentityKeyStore) C.SignalConstPointerFfiIdentityKeyStoreStruct {
return C.SignalConstPointerFfiIdentityKeyStoreStruct{&C.SignalIdentityKeyStore{ return C.SignalConstPointerFfiIdentityKeyStoreStruct{&C.SignalIdentityKeyStore{
ctx: wrapStore(ctx, store), ctx: wrapStore(ctx, store),
get_local_identity_key_pair: C.SignalFfiIdentityKeyStoreGetLocalIdentityKeyPair(C.signal_get_identity_key_pair_callback), get_local_identity_key_pair: C.SignalFfiBridgeIdentityKeyStoreGetLocalIdentityKeyPair(C.signal_get_identity_key_pair_callback),
get_local_registration_id: C.SignalFfiIdentityKeyStoreGetLocalRegistrationId(C.signal_get_local_registration_id_callback), get_local_registration_id: C.SignalFfiBridgeIdentityKeyStoreGetLocalRegistrationId(C.signal_get_local_registration_id_callback),
get_identity_key: C.SignalFfiIdentityKeyStoreGetIdentityKey(C.signal_get_identity_key_callback), get_identity_key: C.SignalFfiBridgeIdentityKeyStoreGetIdentityKey(C.signal_get_identity_key_callback),
save_identity_key: C.SignalFfiIdentityKeyStoreSaveIdentityKey(C.signal_save_identity_key_callback), save_identity_key: C.SignalFfiBridgeIdentityKeyStoreSaveIdentityKey(C.signal_save_identity_key_callback),
is_trusted_identity: C.SignalFfiIdentityKeyStoreIsTrustedIdentity(C.signal_is_trusted_identity_callback), is_trusted_identity: C.SignalFfiBridgeIdentityKeyStoreIsTrustedIdentity(C.signal_is_trusted_identity_callback),
destroy: C.SignalFfiIdentityKeyStoreDestroy(C.signal_destroy_identity_key_store_callback), destroy: C.SignalFfiBridgeIdentityKeyStoreDestroy(C.signal_destroy_identity_key_store_callback),
}} }}
} }

View file

@ -77,9 +77,9 @@ func signal_destroy_kyber_pre_key_store_callback(storeCtx unsafe.Pointer) {
func (ctx *CallbackContext) wrapKyberPreKeyStore(store KyberPreKeyStore) C.SignalConstPointerFfiKyberPreKeyStoreStruct { func (ctx *CallbackContext) wrapKyberPreKeyStore(store KyberPreKeyStore) C.SignalConstPointerFfiKyberPreKeyStoreStruct {
return C.SignalConstPointerFfiKyberPreKeyStoreStruct{&C.SignalKyberPreKeyStore{ return C.SignalConstPointerFfiKyberPreKeyStoreStruct{&C.SignalKyberPreKeyStore{
ctx: wrapStore(ctx, store), ctx: wrapStore(ctx, store),
load_kyber_pre_key: C.SignalFfiKyberPreKeyStoreLoadKyberPreKey(C.signal_load_kyber_pre_key_callback), load_kyber_pre_key: C.SignalFfiBridgeKyberPreKeyStoreLoadKyberPreKey(C.signal_load_kyber_pre_key_callback),
store_kyber_pre_key: C.SignalFfiKyberPreKeyStoreStoreKyberPreKey(C.signal_store_kyber_pre_key_callback), store_kyber_pre_key: C.SignalFfiBridgeKyberPreKeyStoreStoreKyberPreKey(C.signal_store_kyber_pre_key_callback),
mark_kyber_pre_key_used: C.SignalFfiKyberPreKeyStoreMarkKyberPreKeyUsed(C.signal_mark_kyber_pre_key_used_callback), mark_kyber_pre_key_used: C.SignalFfiBridgeKyberPreKeyStoreMarkKyberPreKeyUsed(C.signal_mark_kyber_pre_key_used_callback),
destroy: C.SignalFfiKyberPreKeyStoreDestroy(C.signal_destroy_kyber_pre_key_store_callback), destroy: C.SignalFfiBridgeKyberPreKeyStoreDestroy(C.signal_destroy_kyber_pre_key_store_callback),
}} }}
} }

@ -1 +1 @@
Subproject commit bbc16886cae2feab1cd1fe271ccc651e8860ce96 Subproject commit b58bd7d5dfa0a391486df4210fd83bab96b9b479

View file

@ -629,27 +629,6 @@ typedef struct {
const SignalHttpRequest *raw; const SignalHttpRequest *raw;
} SignalConstPointerHttpRequest; } 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. * A wrapper type for raw UUIDs, because C treats arrays specially in argument position.
*/ */
@ -657,6 +636,13 @@ typedef struct {
uint8_t bytes[16]; uint8_t bytes[16];
} SignalUuid; } 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 { typedef struct {
SignalPrivateKey *raw; SignalPrivateKey *raw;
} SignalMutPointerPrivateKey; } SignalMutPointerPrivateKey;
@ -768,6 +754,10 @@ typedef struct {
const SignalPlaintextContent *raw; const SignalPlaintextContent *raw;
} SignalConstPointerPlaintextContent; } SignalConstPointerPlaintextContent;
typedef struct {
const SignalCiphertextMessage *raw;
} SignalConstPointerCiphertextMessage;
typedef struct { typedef struct {
SignalConnectionInfo *raw; SignalConnectionInfo *raw;
} SignalMutPointerConnectionInfo; } SignalMutPointerConnectionInfo;
@ -792,18 +782,20 @@ typedef struct {
SignalSessionRecord *raw; SignalSessionRecord *raw;
} SignalMutPointerSessionRecord; } 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 { typedef struct {
void *ctx; void *ctx;
SignalFfiSessionStoreLoadSession load_session; SignalFfiBridgeSessionStoreLoadSession load_session;
SignalFfiSessionStoreStoreSession store_session; SignalFfiBridgeSessionStoreStoreSession store_session;
SignalFfiSessionStoreDestroy destroy; SignalFfiBridgeSessionStoreDestroy destroy;
} SignalSessionStore; } SignalFfiBridgeSessionStoreStruct;
typedef SignalFfiBridgeSessionStoreStruct SignalSessionStore;
typedef struct { typedef struct {
const SignalSessionStore *raw; const SignalSessionStore *raw;
@ -818,27 +810,29 @@ typedef struct {
SignalMutPointerPublicKey second; SignalMutPointerPublicKey second;
} SignalPairOfMutPointerPrivateKeyMutPointerPublicKey; } 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 { typedef struct {
void *ctx; void *ctx;
SignalFfiIdentityKeyStoreGetLocalIdentityKeyPair get_local_identity_key_pair; SignalFfiBridgeIdentityKeyStoreGetLocalIdentityKeyPair get_local_identity_key_pair;
SignalFfiIdentityKeyStoreGetLocalRegistrationId get_local_registration_id; SignalFfiBridgeIdentityKeyStoreGetLocalRegistrationId get_local_registration_id;
SignalFfiIdentityKeyStoreGetIdentityKey get_identity_key; SignalFfiBridgeIdentityKeyStoreGetIdentityKey get_identity_key;
SignalFfiIdentityKeyStoreSaveIdentityKey save_identity_key; SignalFfiBridgeIdentityKeyStoreSaveIdentityKey save_identity_key;
SignalFfiIdentityKeyStoreIsTrustedIdentity is_trusted_identity; SignalFfiBridgeIdentityKeyStoreIsTrustedIdentity is_trusted_identity;
SignalFfiIdentityKeyStoreDestroy destroy; SignalFfiBridgeIdentityKeyStoreDestroy destroy;
} SignalIdentityKeyStore; } SignalFfiBridgeIdentityKeyStoreStruct;
typedef SignalFfiBridgeIdentityKeyStoreStruct SignalIdentityKeyStore;
typedef struct { typedef struct {
const SignalIdentityKeyStore *raw; const SignalIdentityKeyStore *raw;
@ -852,21 +846,23 @@ typedef struct {
SignalPreKeyRecord *raw; SignalPreKeyRecord *raw;
} SignalMutPointerPreKeyRecord; } 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 { typedef struct {
void *ctx; void *ctx;
SignalFfiPreKeyStoreLoadPreKey load_pre_key; SignalFfiBridgePreKeyStoreLoadPreKey load_pre_key;
SignalFfiPreKeyStoreStorePreKey store_pre_key; SignalFfiBridgePreKeyStoreStorePreKey store_pre_key;
SignalFfiPreKeyStoreRemovePreKey remove_pre_key; SignalFfiBridgePreKeyStoreRemovePreKey remove_pre_key;
SignalFfiPreKeyStoreDestroy destroy; SignalFfiBridgePreKeyStoreDestroy destroy;
} SignalPreKeyStore; } SignalFfiBridgePreKeyStoreStruct;
typedef SignalFfiBridgePreKeyStoreStruct SignalPreKeyStore;
typedef struct { typedef struct {
const SignalPreKeyStore *raw; const SignalPreKeyStore *raw;
@ -876,18 +872,20 @@ typedef struct {
SignalSignedPreKeyRecord *raw; SignalSignedPreKeyRecord *raw;
} SignalMutPointerSignedPreKeyRecord; } 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 { typedef struct {
void *ctx; void *ctx;
SignalFfiSignedPreKeyStoreLoadSignedPreKey load_signed_pre_key; SignalFfiBridgeSignedPreKeyStoreLoadSignedPreKey load_signed_pre_key;
SignalFfiSignedPreKeyStoreStoreSignedPreKey store_signed_pre_key; SignalFfiBridgeSignedPreKeyStoreStoreSignedPreKey store_signed_pre_key;
SignalFfiSignedPreKeyStoreDestroy destroy; SignalFfiBridgeSignedPreKeyStoreDestroy destroy;
} SignalSignedPreKeyStore; } SignalFfiBridgeSignedPreKeyStoreStruct;
typedef SignalFfiBridgeSignedPreKeyStoreStruct SignalSignedPreKeyStore;
typedef struct { typedef struct {
const SignalSignedPreKeyStore *raw; const SignalSignedPreKeyStore *raw;
@ -897,21 +895,23 @@ typedef struct {
SignalKyberPreKeyRecord *raw; SignalKyberPreKeyRecord *raw;
} SignalMutPointerKyberPreKeyRecord; } 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 { typedef struct {
void *ctx; void *ctx;
SignalFfiKyberPreKeyStoreLoadKyberPreKey load_kyber_pre_key; SignalFfiBridgeKyberPreKeyStoreLoadKyberPreKey load_kyber_pre_key;
SignalFfiKyberPreKeyStoreStoreKyberPreKey store_kyber_pre_key; SignalFfiBridgeKyberPreKeyStoreStoreKyberPreKey store_kyber_pre_key;
SignalFfiKyberPreKeyStoreMarkKyberPreKeyUsed mark_kyber_pre_key_used; SignalFfiBridgeKyberPreKeyStoreMarkKyberPreKeyUsed mark_kyber_pre_key_used;
SignalFfiKyberPreKeyStoreDestroy destroy; SignalFfiBridgeKyberPreKeyStoreDestroy destroy;
} SignalKyberPreKeyStore; } SignalFfiBridgeKyberPreKeyStoreStruct;
typedef SignalFfiBridgeKyberPreKeyStoreStruct SignalKyberPreKeyStore;
typedef struct { typedef struct {
const SignalKyberPreKeyStore *raw; const SignalKyberPreKeyStore *raw;
@ -1047,18 +1047,20 @@ typedef struct {
SignalSenderKeyRecord *raw; SignalSenderKeyRecord *raw;
} SignalMutPointerSenderKeyRecord; } 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 { typedef struct {
void *ctx; void *ctx;
SignalFfiSenderKeyStoreLoadSenderKey load_sender_key; SignalFfiBridgeSenderKeyStoreLoadSenderKey load_sender_key;
SignalFfiSenderKeyStoreStoreSenderKey store_sender_key; SignalFfiBridgeSenderKeyStoreStoreSenderKey store_sender_key;
SignalFfiSenderKeyStoreDestroy destroy; SignalFfiBridgeSenderKeyStoreDestroy destroy;
} SignalSenderKeyStore; } SignalFfiBridgeSenderKeyStoreStruct;
typedef SignalFfiBridgeSenderKeyStoreStruct SignalSenderKeyStore;
typedef struct { typedef struct {
const SignalSenderKeyStore *raw; const SignalSenderKeyStore *raw;
@ -1115,11 +1117,6 @@ typedef struct {
SignalFfiLoggerDestroy destroy; SignalFfiLoggerDestroy destroy;
} SignalFfiLoggerStruct; } SignalFfiLoggerStruct;
typedef struct {
SignalOwnedBuffer first;
SignalOwnedBuffer second;
} SignalPairOfOwnedBufferOfc_ucharOwnedBufferOfc_uchar;
/** /**
* A C callback used to report the results of Rust futures. * A C callback used to report the results of Rust futures.
* *
@ -1130,10 +1127,10 @@ typedef struct {
* completed once. * completed once.
*/ */
typedef struct { 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; const void *context;
SignalCancellationId cancellation_id; SignalCancellationId cancellation_id;
} SignalCPromisePairOfOwnedBufferOfc_ucharOwnedBufferOfc_uchar; } SignalCPromiseOwnedBufferOfc_uchar;
typedef struct { typedef struct {
const SignalUnauthenticatedChatConnection *raw; const SignalUnauthenticatedChatConnection *raw;
@ -1203,18 +1200,20 @@ typedef struct {
const SignalMessageBackupValidationOutcome *raw; const SignalMessageBackupValidationOutcome *raw;
} SignalConstPointerMessageBackupValidationOutcome; } 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 { typedef struct {
void *ctx; void *ctx;
SignalFfiInputStreamRead read; SignalFfiBridgeInputStreamRead read;
SignalFfiInputStreamSkip skip; SignalFfiBridgeInputStreamSkip skip;
SignalFfiInputStreamDestroy destroy; SignalFfiBridgeInputStreamDestroy destroy;
} SignalInputStream; } SignalFfiBridgeInputStreamStruct;
typedef SignalFfiBridgeInputStreamStruct SignalInputStream;
typedef struct { typedef struct {
const SignalInputStream *raw; const SignalInputStream *raw;
@ -1648,7 +1647,9 @@ typedef struct {
SignalValidatingMac *raw; SignalValidatingMac *raw;
} SignalMutPointerValidatingMac; } SignalMutPointerValidatingMac;
typedef SignalInputStream SignalSyncInputStream; typedef SignalFfiBridgeInputStreamStruct SignalFfiBridgeSyncInputStreamStruct;
typedef SignalFfiBridgeSyncInputStreamStruct SignalSyncInputStream;
typedef struct { typedef struct {
const SignalSyncInputStream *raw; 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(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_check_valid_contents(SignalBorrowedBuffer params_bytes);
SignalFfiError *signal_backup_auth_credential_get_backup_id(uint8_t (*out)[16], SignalBorrowedBuffer credential_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_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); 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_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); 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_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); 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(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_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); SignalFfiError *signal_unidentified_sender_message_content_deserialize(SignalMutPointerUnidentifiedSenderMessageContent *out, SignalBorrowedBuffer data);

View file

@ -49,7 +49,7 @@ func Encrypt(ctx context.Context, plaintext []byte, forAddress, localAddress *Ad
return wrapCiphertextMessage(ciphertextMessage.raw), nil 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) callbackCtx := NewCallbackContext(ctx)
defer callbackCtx.Unref() defer callbackCtx.Unref()
var decrypted C.SignalOwnedBuffer = C.SignalOwnedBuffer{} var decrypted C.SignalOwnedBuffer = C.SignalOwnedBuffer{}
@ -57,7 +57,6 @@ func Decrypt(ctx context.Context, message *Message, fromAddress, localAddress *A
&decrypted, &decrypted,
message.constPtr(), message.constPtr(),
fromAddress.constPtr(), fromAddress.constPtr(),
localAddress.constPtr(),
callbackCtx.wrapSessionStore(sessionStore), callbackCtx.wrapSessionStore(sessionStore),
callbackCtx.wrapIdentityKeyStore(identityStore), callbackCtx.wrapIdentityKeyStore(identityStore),
) )

View file

@ -27,14 +27,13 @@ import (
"time" "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) callbackCtx := NewCallbackContext(ctx)
defer callbackCtx.Unref() defer callbackCtx.Unref()
var now C.uint64_t = C.uint64_t(time.Now().Unix()) var now C.uint64_t = C.uint64_t(time.Now().Unix())
signalFfiError := C.signal_process_prekey_bundle( signalFfiError := C.signal_process_prekey_bundle(
bundle.constPtr(), bundle.constPtr(),
forAddress.constPtr(), forAddress.constPtr(),
localAddress.constPtr(),
callbackCtx.wrapSessionStore(sessionStore), callbackCtx.wrapSessionStore(sessionStore),
callbackCtx.wrapIdentityKeyStore(identityStore), callbackCtx.wrapIdentityKeyStore(identityStore),
now, now,

View file

@ -76,9 +76,9 @@ func signal_destroy_pre_key_store_callback(storeCtx unsafe.Pointer) {
func (ctx *CallbackContext) wrapPreKeyStore(store PreKeyStore) C.SignalConstPointerFfiPreKeyStoreStruct { func (ctx *CallbackContext) wrapPreKeyStore(store PreKeyStore) C.SignalConstPointerFfiPreKeyStoreStruct {
return C.SignalConstPointerFfiPreKeyStoreStruct{&C.SignalPreKeyStore{ return C.SignalConstPointerFfiPreKeyStoreStruct{&C.SignalPreKeyStore{
ctx: wrapStore(ctx, store), ctx: wrapStore(ctx, store),
load_pre_key: C.SignalFfiPreKeyStoreLoadPreKey(C.signal_load_pre_key_callback), load_pre_key: C.SignalFfiBridgePreKeyStoreLoadPreKey(C.signal_load_pre_key_callback),
store_pre_key: C.SignalFfiPreKeyStoreStorePreKey(C.signal_store_pre_key_callback), store_pre_key: C.SignalFfiBridgePreKeyStoreStorePreKey(C.signal_store_pre_key_callback),
remove_pre_key: C.SignalFfiPreKeyStoreRemovePreKey(C.signal_remove_pre_key_callback), remove_pre_key: C.SignalFfiBridgePreKeyStoreRemovePreKey(C.signal_remove_pre_key_callback),
destroy: C.SignalFfiPreKeyStoreDestroy(C.signal_destroy_pre_key_store_callback), destroy: C.SignalFfiBridgePreKeyStoreDestroy(C.signal_destroy_pre_key_store_callback),
}} }}
} }

View file

@ -70,8 +70,8 @@ func signal_destroy_sender_key_store_callback(storeCtx unsafe.Pointer) {
func (ctx *CallbackContext) wrapSenderKeyStore(store SenderKeyStore) C.SignalConstPointerFfiSenderKeyStoreStruct { func (ctx *CallbackContext) wrapSenderKeyStore(store SenderKeyStore) C.SignalConstPointerFfiSenderKeyStoreStruct {
return C.SignalConstPointerFfiSenderKeyStoreStruct{&C.SignalSenderKeyStore{ return C.SignalConstPointerFfiSenderKeyStoreStruct{&C.SignalSenderKeyStore{
ctx: wrapStore(ctx, store), ctx: wrapStore(ctx, store),
load_sender_key: C.SignalFfiSenderKeyStoreLoadSenderKey(C.signal_load_sender_key_callback), load_sender_key: C.SignalFfiBridgeSenderKeyStoreLoadSenderKey(C.signal_load_sender_key_callback),
store_sender_key: C.SignalFfiSenderKeyStoreStoreSenderKey(C.signal_store_sender_key_callback), store_sender_key: C.SignalFfiBridgeSenderKeyStoreStoreSenderKey(C.signal_store_sender_key_callback),
destroy: C.SignalFfiSenderKeyStoreDestroy(C.signal_destroy_sender_key_store_callback), destroy: C.SignalFfiBridgeSenderKeyStoreDestroy(C.signal_destroy_sender_key_store_callback),
}} }}
} }

View file

@ -30,7 +30,7 @@ import (
"go.mau.fi/mautrix-signal/pkg/libsignalgo" "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() ctx := context.TODO()
bobPreKey, err := libsignalgo.GeneratePrivateKey() bobPreKey, err := libsignalgo.GeneratePrivateKey()
@ -86,7 +86,7 @@ func initializeSessions(t *testing.T, aliceStore, bobStore *InMemorySignalProtoc
assert.NoError(t, err) assert.NoError(t, err)
// Alice processes the bundle // 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) assert.NoError(t, err)
record, err := aliceStore.LoadSession(ctx, bobAddress) record, err := aliceStore.LoadSession(ctx, bobAddress)
@ -132,7 +132,7 @@ func TestSessionCipher(t *testing.T) {
aliceStore := NewInMemorySignalProtocolStore() aliceStore := NewInMemorySignalProtocolStore()
bobStore := NewInMemorySignalProtocolStore() bobStore := NewInMemorySignalProtocolStore()
initializeSessions(t, aliceStore, bobStore, bobAddress, aliceAddress) initializeSessions(t, aliceStore, bobStore, bobAddress)
alicePlaintext := []byte{8, 6, 7, 5, 3, 0, 9} alicePlaintext := []byte{8, 6, 7, 5, 3, 0, 9}
@ -163,7 +163,7 @@ func TestSessionCipher(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
aliceCiphertext2, err := libsignalgo.DeserializeMessage(bobCiphertext2Serialized) aliceCiphertext2, err := libsignalgo.DeserializeMessage(bobCiphertext2Serialized)
assert.NoError(t, err) 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.NoError(t, err)
assert.Equal(t, bobPlaintext2, alicePlaintext2) assert.Equal(t, bobPlaintext2, alicePlaintext2)
} }
@ -183,7 +183,7 @@ func TestSessionCipherWithBadStore(t *testing.T) {
aliceStore := NewInMemorySignalProtocolStore() aliceStore := NewInMemorySignalProtocolStore()
bobStore := &BadInMemorySignalProtocolStore{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} alicePlaintext := []byte{8, 6, 7, 5, 3, 0, 9}
@ -216,7 +216,7 @@ func TestSealedSenderEncrypt_Repeated(t *testing.T) {
aliceStore := NewInMemorySignalProtocolStore() aliceStore := NewInMemorySignalProtocolStore()
bobStore := NewInMemorySignalProtocolStore() bobStore := NewInMemorySignalProtocolStore()
initializeSessions(t, aliceStore, bobStore, bobAddress, aliceAddress) initializeSessions(t, aliceStore, bobStore, bobAddress)
trustRoot, err := libsignalgo.GenerateIdentityKeyPair() trustRoot, err := libsignalgo.GenerateIdentityKeyPair()
assert.NoError(t, err) assert.NoError(t, err)
@ -252,18 +252,15 @@ func TestArchiveSession(t *testing.T) {
ctx := context.TODO() ctx := context.TODO()
setupLogging() setupLogging()
aliceACI := uuid.New()
bobACI := uuid.New() bobACI := uuid.New()
aliceAddress, err := libsignalgo.NewACIServiceID(aliceACI).Address(1)
assert.NoError(t, err)
bobAddress, err := libsignalgo.NewACIServiceID(bobACI).Address(1) bobAddress, err := libsignalgo.NewACIServiceID(bobACI).Address(1)
assert.NoError(t, err) assert.NoError(t, err)
aliceStore := NewInMemorySignalProtocolStore() aliceStore := NewInMemorySignalProtocolStore()
bobStore := NewInMemorySignalProtocolStore() bobStore := NewInMemorySignalProtocolStore()
initializeSessions(t, aliceStore, bobStore, bobAddress, aliceAddress) initializeSessions(t, aliceStore, bobStore, bobAddress)
session, err := aliceStore.LoadSession(ctx, bobAddress) session, err := aliceStore.LoadSession(ctx, bobAddress)
assert.NoError(t, err) assert.NoError(t, err)
@ -318,7 +315,7 @@ func TestSealedSenderGroupCipher(t *testing.T) {
bobStore := NewInMemorySignalProtocolStore() bobStore := NewInMemorySignalProtocolStore()
initializeSessions(t, aliceStore, bobStore, bobAddress, aliceAddress) initializeSessions(t, aliceStore, bobStore, bobAddress)
trustRoot, err := libsignalgo.GenerateIdentityKeyPair() trustRoot, err := libsignalgo.GenerateIdentityKeyPair()
assert.NoError(t, err) assert.NoError(t, err)

View file

@ -67,8 +67,8 @@ func signal_destroy_session_store_callback(storeCtx unsafe.Pointer) {
func (ctx *CallbackContext) wrapSessionStore(store SessionStore) C.SignalConstPointerFfiSessionStoreStruct { func (ctx *CallbackContext) wrapSessionStore(store SessionStore) C.SignalConstPointerFfiSessionStoreStruct {
return C.SignalConstPointerFfiSessionStoreStruct{&C.SignalSessionStore{ return C.SignalConstPointerFfiSessionStoreStruct{&C.SignalSessionStore{
ctx: wrapStore(ctx, store), ctx: wrapStore(ctx, store),
load_session: C.SignalFfiSessionStoreLoadSession(C.signal_load_session_callback), load_session: C.SignalFfiBridgeSessionStoreLoadSession(C.signal_load_session_callback),
store_session: C.SignalFfiSessionStoreStoreSession(C.signal_store_session_callback), store_session: C.SignalFfiBridgeSessionStoreStoreSession(C.signal_store_session_callback),
destroy: C.SignalFfiSessionStoreDestroy(C.signal_destroy_session_store_callback), destroy: C.SignalFfiBridgeSessionStoreDestroy(C.signal_destroy_session_store_callback),
}} }}
} }

View file

@ -67,8 +67,8 @@ func signal_destroy_signed_pre_key_store_callback(storeCtx unsafe.Pointer) {
func (ctx *CallbackContext) wrapSignedPreKeyStore(store SignedPreKeyStore) C.SignalConstPointerFfiSignedPreKeyStoreStruct { func (ctx *CallbackContext) wrapSignedPreKeyStore(store SignedPreKeyStore) C.SignalConstPointerFfiSignedPreKeyStoreStruct {
return C.SignalConstPointerFfiSignedPreKeyStoreStruct{&C.SignalSignedPreKeyStore{ return C.SignalConstPointerFfiSignedPreKeyStoreStruct{&C.SignalSignedPreKeyStore{
ctx: wrapStore(ctx, store), ctx: wrapStore(ctx, store),
load_signed_pre_key: C.SignalFfiSignedPreKeyStoreLoadSignedPreKey(C.signal_load_signed_pre_key_callback), load_signed_pre_key: C.SignalFfiBridgeSignedPreKeyStoreLoadSignedPreKey(C.signal_load_signed_pre_key_callback),
store_signed_pre_key: C.SignalFfiSignedPreKeyStoreStoreSignedPreKey(C.signal_store_signed_pre_key_callback), store_signed_pre_key: C.SignalFfiBridgeSignedPreKeyStoreStoreSignedPreKey(C.signal_store_signed_pre_key_callback),
destroy: C.SignalFfiSignedPreKeyStoreDestroy(C.signal_destroy_signed_pre_key_store_callback), destroy: C.SignalFfiBridgeSignedPreKeyStoreDestroy(C.signal_destroy_signed_pre_key_store_callback),
}} }}
} }

View file

@ -2,4 +2,4 @@
package libsignalgo package libsignalgo
const Version = "v0.93.2" const Version = "v0.92.1"

View file

@ -110,9 +110,6 @@ func (mc *MessageConverter) ToSignal(
return nil, fmt.Errorf("failed to convert sticker: %w", err) return nil, fmt.Errorf("failed to convert sticker: %w", err)
} }
att.Flags = proto.Uint32(uint32(signalpb.AttachmentPointer_BORDERLESS)) att.Flags = proto.Uint32(uint32(signalpb.AttachmentPointer_BORDERLESS))
dm.Sticker = ParseStickerMeta(content.Info.BridgedSticker)
if dm.Sticker == nil {
var emoji *string var emoji *string
// TODO check for single grapheme cluster? // TODO check for single grapheme cluster?
if len([]rune(content.Body)) == 1 { if len([]rune(content.Body)) == 1 {
@ -124,10 +121,10 @@ func (mc *MessageConverter) ToSignal(
PackId: make([]byte, 16), PackId: make([]byte, 16),
PackKey: make([]byte, 32), PackKey: make([]byte, 32),
StickerId: proto.Uint32(0), StickerId: proto.Uint32(0),
Data: att,
Emoji: emoji, Emoji: emoji,
} }
}
dm.Sticker.Data = att
case event.MsgLocation: case event.MsgLocation:
lat, lon, err := parseGeoURI(content.GeoURI) lat, lon, err := parseGeoURI(content.GeoURI)
if err != nil { if err != nil {

View file

@ -468,16 +468,20 @@ func (mc *MessageConverter) convertStickerToMatrix(ctx context.Context, sticker
converted.Content.Info.Height = 200 converted.Content.Info.Height = 200
} }
converted.Content.Body = sticker.GetEmoji() 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.Type = event.EventSticker
converted.Content.MsgType = "" 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 return converted
} }

View file

@ -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 <https://www.gnu.org/licenses/>.
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
}

View file

@ -34,7 +34,6 @@ const (
directMediaTypeGroupAvatar directMediaType = 1 directMediaTypeGroupAvatar directMediaType = 1
directMediaTypeProfileAvatar directMediaType = 2 directMediaTypeProfileAvatar directMediaType = 2
directMediaTypePlaintextDigestAttachment directMediaType = 3 directMediaTypePlaintextDigestAttachment directMediaType = 3
directMediaTypeSticker directMediaType = 4
) )
type DirectMediaInfo interface { type DirectMediaInfo interface {
@ -45,7 +44,6 @@ var (
_ DirectMediaInfo = (*DirectMediaAttachment)(nil) _ DirectMediaInfo = (*DirectMediaAttachment)(nil)
_ DirectMediaInfo = (*DirectMediaGroupAvatar)(nil) _ DirectMediaInfo = (*DirectMediaGroupAvatar)(nil)
_ DirectMediaInfo = (*DirectMediaProfileAvatar)(nil) _ DirectMediaInfo = (*DirectMediaProfileAvatar)(nil)
_ DirectMediaInfo = (*DirectMediaSticker)(nil)
) )
type DirectMediaAttachment struct { type DirectMediaAttachment struct {
@ -129,30 +127,6 @@ func (m DirectMediaProfileAvatar) AsMediaID() (mediaID networkid.MediaID, err er
return networkid.MediaID(buf.Bytes()), nil 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) { func ParseDirectMediaInfo(mediaID networkid.MediaID) (_ DirectMediaInfo, err error) {
mediaIDLen := len(mediaID) mediaIDLen := len(mediaID)
if mediaIDLen == 0 { if mediaIDLen == 0 {
@ -226,15 +200,6 @@ func ParseDirectMediaInfo(mediaID networkid.MediaID) (_ DirectMediaInfo, err err
info.ProfileAvatarPath = string(profileAvatarPath) info.ProfileAvatarPath = string(profileAvatarPath)
} }
return &info, nil 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) return nil, fmt.Errorf("invalid direct media type %d", mediaType)

View file

@ -35,7 +35,6 @@ import (
"github.com/rs/zerolog" "github.com/rs/zerolog"
"go.mau.fi/util/fallocate" "go.mau.fi/util/fallocate"
"go.mau.fi/util/pkcs7"
"go.mau.fi/util/random" "go.mau.fi/util/random"
"google.golang.org/protobuf/proto" "google.golang.org/protobuf/proto"
@ -137,15 +136,6 @@ func DownloadAttachment(
const MACLength = 32 const MACLength = 32
const IVLength = 16 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) { func decryptAttachment(body, key, digest []byte, plaintextDigest bool, size uint32) ([]byte, error) {
if !plaintextDigest { if !plaintextDigest {
hash := sha256.Sum256(body) hash := sha256.Sum256(body)
@ -153,7 +143,12 @@ func decryptAttachment(body, key, digest []byte, plaintextDigest bool, size uint
return nil, ErrInvalidDigestForAttachment 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 { if err != nil {
return nil, err 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) { func (cli *Client) UploadAttachment(ctx context.Context, body []byte) (*signalpb.AttachmentPointer, error) {
log := zerolog.Ctx(ctx).With().Str("func", "upload attachment").Logger() log := zerolog.Ctx(ctx).With().Str("func", "upload attachment").Logger()
keys := random.Bytes(64) // combined AES and MAC keys 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) body = extend(body, paddedLen)
encryptedWithMAC, err := macAndAESEncrypt(keys, body) encrypted, err := aesEncrypt(keys[:32], body)
if err != nil { if err != nil {
return nil, err return nil, err
} }
encryptedWithMAC := appendMAC(keys[32:], encrypted)
// Get upload attributes from Signal server // Get upload attributes from Signal server
attributesPath := "/v4/attachments/form/upload" attributesPath := "/v4/attachments/form/upload"
@ -479,10 +467,13 @@ func aesDecrypt(key, ciphertext []byte) ([]byte, error) {
} }
iv := ciphertext[:IVLength] iv := ciphertext[:IVLength]
ciphertext = ciphertext[IVLength:]
mode := cipher.NewCBCDecrypter(block, iv) mode := cipher.NewCBCDecrypter(block, iv)
mode.CryptBlocks(ciphertext, ciphertext) 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) { 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 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) iv := random.Bytes(16)
mode := cipher.NewCBCEncrypter(block, iv) mode := cipher.NewCBCEncrypter(block, iv)
mode.CryptBlocks(plaintext, plaintext) mode.CryptBlocks(ciphertext, plaintext)
return append(iv, plaintext...), nil return append(iv, ciphertext...), nil
} }

View file

@ -413,10 +413,6 @@ func (cli *Client) FetchAndProcessPreKey(ctx context.Context, theirServiceID lib
if cli.Store.RecipientStore.IsUnregistered(ctx, theirServiceID) { if cli.Store.RecipientStore.IsUnregistered(ctx, theirServiceID) {
return fmt.Errorf("%w (cached)", ErrUnregisteredUser) 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 // Fetch prekey
deviceIDPath := "/*" deviceIDPath := "/*"
if specificDeviceID >= 0 { if specificDeviceID >= 0 {
@ -522,7 +518,6 @@ func (cli *Client) FetchAndProcessPreKey(ctx context.Context, theirServiceID lib
ctx, ctx,
preKeyBundle, preKeyBundle,
address, address,
localAddress,
cli.Store.ACISessionStore, cli.Store.ACISessionStore,
cli.Store.ACIIdentityStore, cli.Store.ACIIdentityStore,
) )

View file

@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.36.11 // protoc-gen-go v1.36.11
// protoc v7.34.1 // protoc v6.33.5
// source: ContactDiscovery.proto // source: ContactDiscovery.proto
// Copyright 2021 Signal Messenger, LLC // Copyright 2021 Signal Messenger, LLC

View file

@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.36.11 // protoc-gen-go v1.36.11
// protoc v7.34.1 // protoc v6.33.5
// source: DeviceName.proto // source: DeviceName.proto
// Copyright 2018 Signal Messenger, LLC // Copyright 2018 Signal Messenger, LLC

View file

@ -5,7 +5,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.36.11 // protoc-gen-go v1.36.11
// protoc v7.34.1 // protoc v6.33.5
// source: Groups.proto // source: Groups.proto
package signalpb package signalpb

View file

@ -5,7 +5,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.36.11 // protoc-gen-go v1.36.11
// protoc v7.34.1 // protoc v6.33.5
// source: Provisioning.proto // source: Provisioning.proto
package signalpb package signalpb

View file

@ -5,7 +5,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.36.11 // protoc-gen-go v1.36.11
// protoc v7.34.1 // protoc v6.33.5
// source: SignalService.proto // source: SignalService.proto
package signalpb package signalpb

View file

@ -6,7 +6,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.36.11 // protoc-gen-go v1.36.11
// protoc v7.34.1 // protoc v6.33.5
// source: StickerResources.proto // source: StickerResources.proto
package signalpb package signalpb

View file

@ -6,7 +6,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.36.11 // protoc-gen-go v1.36.11
// protoc v7.34.1 // protoc v6.33.5
// source: StorageService.proto // source: StorageService.proto
package signalpb package signalpb
@ -1401,7 +1401,6 @@ type GroupV2Record struct {
HideStory bool `protobuf:"varint,8,opt,name=hideStory,proto3" json:"hideStory,omitempty"` 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"` 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"` 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 unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
} }
@ -1506,13 +1505,6 @@ func (x *GroupV2Record) GetAvatarColor() AvatarColor {
return AvatarColor_A100 return AvatarColor_A100
} }
func (x *GroupV2Record) GetVerifiedNameHash() []byte {
if x != nil {
return x.VerifiedNameHash
}
return nil
}
type Payments struct { type Payments struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"` 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" + "\vwhitelisted\x18\x03 \x01(\bR\vwhitelisted\x12\x1a\n" +
"\barchived\x18\x04 \x01(\bR\barchived\x12\"\n" + "\barchived\x18\x04 \x01(\bR\barchived\x12\"\n" +
"\fmarkedUnread\x18\x05 \x01(\bR\fmarkedUnread\x120\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" + "\rGroupV2Record\x12\x1c\n" +
"\tmasterKey\x18\x01 \x01(\fR\tmasterKey\x12\x18\n" + "\tmasterKey\x18\x01 \x01(\fR\tmasterKey\x12\x18\n" +
"\ablocked\x18\x02 \x01(\bR\ablocked\x12 \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" + "\thideStory\x18\b \x01(\bR\thideStory\x12P\n" +
"\rstorySendMode\x18\n" + "\rstorySendMode\x18\n" +
" \x01(\x0e2*.signalservice.GroupV2Record.StorySendModeR\rstorySendMode\x12A\n" + " \x01(\x0e2*.signalservice.GroupV2Record.StorySendModeR\rstorySendMode\x12A\n" +
"\vavatarColor\x18\v \x01(\x0e2\x1a.signalservice.AvatarColorH\x00R\vavatarColor\x88\x01\x01\x12*\n" + "\vavatarColor\x18\v \x01(\x0e2\x1a.signalservice.AvatarColorH\x00R\vavatarColor\x88\x01\x01\"7\n" +
"\x10verifiedNameHash\x18\f \x01(\fR\x10verifiedNameHash\"7\n" +
"\rStorySendMode\x12\v\n" + "\rStorySendMode\x12\v\n" +
"\aDEFAULT\x10\x00\x12\f\n" + "\aDEFAULT\x10\x00\x12\f\n" +
"\bDISABLED\x10\x01\x12\v\n" + "\bDISABLED\x10\x01\x12\v\n" +

View file

@ -172,7 +172,6 @@ message GroupV2Record {
reserved /* storySendEnabled */ 9; reserved /* storySendEnabled */ 9;
StorySendMode storySendMode = 10; StorySendMode storySendMode = 10;
optional AvatarColor avatarColor = 11; optional AvatarColor avatarColor = 11;
bytes verifiedNameHash = 12; // SHA-256 of UTF-8 encoded decrypted group title that was last verified
} }
message Payments { message Payments {

View file

@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.36.11 // protoc-gen-go v1.36.11
// protoc v7.34.1 // protoc v6.33.5
// source: UnidentifiedDelivery.proto // source: UnidentifiedDelivery.proto
// Copyright 2018 Signal Messenger, LLC // Copyright 2018 Signal Messenger, LLC

View file

@ -6,7 +6,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.36.11 // protoc-gen-go v1.36.11
// protoc v7.34.1 // protoc v6.33.5
// source: WebSocketResources.proto // source: WebSocketResources.proto
package signalpb package signalpb

View file

@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.36.11 // protoc-gen-go v1.36.11
// protoc v7.34.1 // protoc v6.33.5
// source: backuppb/Backup.proto // source: backuppb/Backup.proto
package backuppb package backuppb

View file

@ -1,8 +1,8 @@
#!/bin/bash #!/bin/bash
set -euo pipefail set -euo pipefail
ANDROID_GIT_REVISION=${1:-439760e7732585bfd078d92d93732c04cc31e29e} ANDROID_GIT_REVISION=${1:-dfd2f7baf96825834f784900ce644e9ead8a9a89}
DESKTOP_GIT_REVISION=${1:-1b2a3e7b283c32c5654a39da12fc04139fd26dbd} DESKTOP_GIT_REVISION=${1:-60a1e125452ee672d8747564d0055d5bfec9f679}
update_proto() { update_proto() {
case "$1" in case "$1" in

View file

@ -243,16 +243,11 @@ func (cli *Client) decryptCiphertextEnvelope(
if identityStore == nil { if identityStore == nil {
return nil, fmt.Errorf("no identity store for destination service ID %s", destinationServiceID) 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) { plaintext, ciphertextHash, err := cli.bufferedDecryptTxn(ctx, ciphertext, serverTimestamp, func(ctx context.Context) ([]byte, error) {
return libsignalgo.Decrypt( return libsignalgo.Decrypt(
ctx, ctx,
message, message,
senderAddress, senderAddress,
destinationAddress,
sessionStore, sessionStore,
identityStore, identityStore,
) )

View file

@ -384,7 +384,15 @@ func syncMessageFromSoloEditMessage(editMessage *signalpb.EditMessage, result Su
} }
func syncMessageFromReadReceiptMessage(ctx context.Context, receiptMessage *signalpb.ReceiptMessage, messageSender libsignalgo.ServiceID) *signalpb.Content { 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 return nil
} }
read := []*signalpb.SyncMessage_Read{} read := []*signalpb.SyncMessage_Read{}

View file

@ -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 <https://www.gnu.org/licenses/>.
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))
}

View file

@ -28,7 +28,6 @@ import (
"net/http" "net/http"
"runtime" "runtime"
"strings" "strings"
"time"
"github.com/rs/zerolog" "github.com/rs/zerolog"
@ -130,7 +129,6 @@ func SendHTTPRequest(ctx context.Context, host, method, path string, opt *HTTPRe
} else { } else {
req.Header.Set("Content-Type", string(ContentTypeJSON)) 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("Content-Length", fmt.Sprintf("%d", len(opt.Body)))
req.Header.Set("User-Agent", UserAgent) req.Header.Set("User-Agent", UserAgent)
req.Header.Set("X-Signal-Agent", SignalAgent) req.Header.Set("X-Signal-Agent", SignalAgent)
@ -141,14 +139,12 @@ func SendHTTPRequest(ctx context.Context, host, method, path string, opt *HTTPRe
httpReqCounter++ httpReqCounter++
log = log.With().Int("request_number", httpReqCounter).Logger() log = log.With().Int("request_number", httpReqCounter).Logger()
log.Trace().Msg("Sending HTTP request") log.Trace().Msg("Sending HTTP request")
start := time.Now()
resp, err := SignalHTTPClient.Do(req) resp, err := SignalHTTPClient.Do(req)
dur := time.Since(start)
if err != nil { if err != nil {
log.Err(err).Dur("duration", dur).Msg("Error sending request") log.Err(err).Msg("Error sending request")
return nil, err 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 return resp, nil
} }