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

Compare commits

...

28 commits

Author SHA1 Message Date
Tulir Asokan
0df937749b dependencies: update mautrix-go 2026-05-13 15:05:37 +03:00
Tulir Asokan
14592ffdcc dependencies: update mautrix-go 2026-05-12 17:52:48 +03:00
SpiritCroc
41a37cd184
capabilities: drop webp to only partial support (#649)
Co-authored-by: Tulir Asokan <tulir@maunium.net>
2026-05-12 11:43:06 +02:00
Tulir Asokan
4545def017 signalmeow/web: log request durations 2026-05-11 16:16:36 +03:00
Tulir Asokan
9cdd4c9963 signalmeow: update protobufs 2026-05-08 16:57:56 +03:00
Tulir Asokan
4f1ebf7aa2 dependencies: update mautrix-go 2026-05-08 16:56:40 +03:00
Tulir Asokan
06bdbfc2ca libsignal: update to v0.93.2 2026-05-08 16:55:42 +03:00
Tulir Asokan
90487a25e0 imagepack: return 404 on incorrectly formatted link 2026-05-06 13:47:09 +03:00
Tulir Asokan
0813d39095 .github: add version command to bug report template 2026-05-06 13:23:56 +03:00
Tulir Asokan
0214ecc600 msgconv/imagepack: fix stickers with no bridged metadata 2026-05-04 17:32:04 +03:00
Tulir Asokan
694858478c client: add stub ListImagePacks method 2026-04-30 15:49:16 +03:00
Tulir Asokan
9ebd8d4dd0 .github: add another item to bug report template 2026-04-30 13:23:08 +03:00
Tulir Asokan
1f1b645213 client: add support for importing Signal sticker packs 2026-04-30 13:17:56 +03:00
Tulir Asokan
14559977fc directmedia: fix response metadata for avatars 2026-04-30 12:05:00 +03:00
Tulir Asokan
a27b6745b2 dependencies: update mautrix-go 2026-04-29 09:10:31 +03:00
Tulir Asokan
9e9dc8b548 signalmeow/sticker: add methods for creating and fetching sticker packs 2026-04-28 14:24:30 +03:00
Tulir Asokan
c2afb9f113 signalmeow/web: sent ContentLength field in request 2026-04-28 14:24:30 +03:00
Tulir Asokan
6beb2faa9f msgconv/from-matrix: preserve sticker pack metadata when sending to signal 2026-04-28 14:24:30 +03:00
Tulir Asokan
2b2a3b036f signalmeow/attachments: use go-util for pkcs7 padding 2026-04-27 20:50:07 +03:00
Tulir Asokan
d4b2659f96 signalmeow/sending: remove unnecessary warnings for receipt sync messages 2026-04-27 12:20:03 +03:00
Tulir Asokan
1f45d1af1a Bump version to v26.04 2026-04-16 16:44:51 +03:00
Tulir Asokan
fd61f51ed9 signalmeow/storageservice: handle binary uuids in contact records 2026-04-15 14:28:57 +03:00
Tulir Asokan
e0901b648f handlesignal: add support for admin deletes 2026-04-13 16:58:43 +03:00
Tulir Asokan
2297e6b48b signalmeow: update protobufs
Content and SyncMessage switched to use oneofs, which is why a lot of code changed
2026-04-13 16:49:08 +03:00
Tulir Asokan
38f2ba9430 signalmeow/groups: use shared error type for unknown group master key 2026-04-13 16:49:08 +03:00
Tulir Asokan
952e7c473b libsignal: update to v0.92.1 2026-04-13 16:49:08 +03:00
Rowan
fdb9a61601
docker: add missing protobuf-dev package to non-ci dockerfile (#646) 2026-04-13 16:49:01 +03:00
Tulir Asokan
1c531e03da signalmeow/groups: catch missing group master key 2026-04-12 23:16:33 +03:00
59 changed files with 3336 additions and 1836 deletions

View file

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

View file

@ -1,3 +1,12 @@
# v26.04
* Updated libsignal to v0.92.1
* Added support for admin message deletes from Signal.
* Added support for binary service IDs in storage service.
* Fixed `private_chat_portal_meta` option not setting DM room names correctly.
* Fixed panic if user is logged out during initial chat sync.
* Fixed avatar upload failing when creating new Signal group.
# v26.03 # v26.03
* Switched to sending binary service ID fields in outgoing messages. * Switched to sending binary service ID fields in outgoing messages.

View file

@ -1,6 +1,6 @@
# -- Build libsignal (with Rust) -- # -- Build libsignal (with Rust) --
FROM rust:1-alpine AS rust-builder FROM rust:1-alpine AS rust-builder
RUN apk add --no-cache git make cmake protoc musl-dev g++ clang-dev RUN apk add --no-cache git make cmake protoc musl-dev g++ clang-dev protobuf-dev
WORKDIR /build WORKDIR /build
# Copy all files needed for Rust build, and no Go files # Copy all files needed for Rust build, and no Go files

View file

@ -37,7 +37,7 @@ var m = mxmain.BridgeMain{
Name: "mautrix-signal", Name: "mautrix-signal",
URL: "https://github.com/mautrix/signal", URL: "https://github.com/mautrix/signal",
Description: "A Matrix-Signal puppeting bridge.", Description: "A Matrix-Signal puppeting bridge.",
Version: "26.03", Version: "26.04",
SemCalVer: true, SemCalVer: true,
Connector: &connector.SignalConnector{}, Connector: &connector.SignalConnector{},

28
go.mod
View file

@ -2,7 +2,7 @@ module go.mau.fi/mautrix-signal
go 1.25.0 go 1.25.0
toolchain go1.26.1 toolchain go1.26.2
tool go.mau.fi/util/cmd/maubuild tool go.mau.fi/util/cmd/maubuild
@ -11,16 +11,17 @@ 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.0 github.com/rs/zerolog v1.35.1
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.8-0.20260406161447-0300c476893a go.mau.fi/util v0.9.9-0.20260511124621-9241e81bdf25
golang.org/x/crypto v0.49.0 golang.org/x/crypto v0.50.0
golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f
golang.org/x/net v0.52.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.26.5-0.20260410220226-744570e6f1f5 maunium.net/go/mautrix v0.27.1-0.20260513120123-5fba7e3afae4
) )
require ( require (
@ -28,11 +29,11 @@ require (
github.com/coreos/go-systemd/v22 v22.7.0 // indirect github.com/coreos/go-systemd/v22 v22.7.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/kr/pretty v0.3.1 // indirect github.com/kr/pretty v0.3.1 // indirect
github.com/lib/pq v1.12.0 // 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.37 // indirect github.com/mattn/go-sqlite3 v1.14.44 // indirect
github.com/petermattis/goid v0.0.0-20260226131333-17d1149c6ac6 // 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
github.com/rs/xid v1.6.0 // indirect github.com/rs/xid v1.6.0 // indirect
@ -42,10 +43,9 @@ require (
github.com/tidwall/sjson v1.2.5 // indirect github.com/tidwall/sjson v1.2.5 // indirect
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.34.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.42.0 // indirect golang.org/x/text v0.36.0 // indirect
golang.org/x/text v0.35.0 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
maunium.net/go/mauflag v1.0.0 // indirect maunium.net/go/mauflag v1.0.0 // indirect

48
go.sum
View file

@ -22,18 +22,18 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lib/pq v1.12.0 h1:mC1zeiNamwKBecjHarAr26c/+d8V5w/u4J0I/yASbJo= github.com/lib/pq v1.12.3 h1:tTWxr2YLKwIvK90ZXEw8GP7UFHtcbTtty8zsI+YjrfQ=
github.com/lib/pq v1.12.0/go.mod h1:/p+8NSbOcwzAEI7wiMXFlgydTwcgTr3OSKMsD2BitpA= github.com/lib/pq v1.12.3/go.mod h1:/p+8NSbOcwzAEI7wiMXFlgydTwcgTr3OSKMsD2BitpA=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
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.37 h1:3DOZp4cXis1cUIpCfXLtmlGolNLp2VEqhiB/PARNBIg= github.com/mattn/go-sqlite3 v1.14.44 h1:3VSe+xafpbzsLbdr2AWlAZk9yRHiBhTBakioXaCKTF8=
github.com/mattn/go-sqlite3 v1.14.37/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/mattn/go-sqlite3 v1.14.44/go.mod h1:pjEuOr8IwzLJP2MfGeTb0A35jauH+C2kbHKBr7yXKVQ=
github.com/petermattis/goid v0.0.0-20260226131333-17d1149c6ac6 h1:rh2lKw/P/EqHa724vYH2+VVQ1YnW4u6EOXl0PMAovZE= github.com/petermattis/goid v0.0.0-20260330135022-df67b199bc81 h1:WDsQxOJDy0N1VRAjXLpi8sCEZRSGarLWQevDxpTBRrM=
github.com/petermattis/goid v0.0.0-20260226131333-17d1149c6ac6/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=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@ -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.0 h1:VD0ykx7HMiMJytqINBsKcbLS+BJ4WYjz+05us+LRTdI= github.com/rs/zerolog v1.35.1 h1:m7xQeoiLIiV0BCEY4Hs+j2NG4Gp2o2KPKmhnnLiazKI=
github.com/rs/zerolog v1.35.0/go.mod h1:EjML9kdfa/RMA7h/6z6pYmq1ykOuA8/mjWaEvGI+jcw= github.com/rs/zerolog v1.35.1/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,25 +61,25 @@ 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.8-0.20260406161447-0300c476893a h1:OQQF3rTJH10l6+dcP0OKnYbNDMBTGoIZZINNJm8QBG8= go.mau.fi/util v0.9.9-0.20260511124621-9241e81bdf25 h1:YPEmc+li7TF6C9AdRTcSLMb6yCHdF27/wNT7kFLIVNg=
go.mau.fi/util v0.9.8-0.20260406161447-0300c476893a/go.mod h1:5T2f3ZWZFAGgmFwg3dGw7YK6kIsb9lryDzvynoR98pE= go.mau.fi/util v0.9.9-0.20260511124621-9241e81bdf25/go.mod h1:jE9FfhbgEgAwxei6lomO9v8zdCIATcquONUu4vjRwSs=
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.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4= golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI=
golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA= golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q=
golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 h1:jiDhWWeC7jfWqR9c/uplMOqJ0sbNlNWv0UkzE0vX1MA= golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f h1:W3F4c+6OLc6H2lb//N1q4WpJkhzJCK5J6kUi1NTVXfM=
golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90/go.mod h1:xE1HEv6b+1SCZ5/uscMRjUBKtIxworgEcEi+/n9NQDQ= golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f/go.mod h1:J1xhfL/vlindoeF/aINzNzt2Bket5bjo9sdOYzOsU80=
golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI= golang.org/x/mod v0.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM=
golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY= golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU=
golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0= golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA=
golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw= golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs=
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8= golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg=
golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA= golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164=
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@ -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.26.5-0.20260410220226-744570e6f1f5 h1:icMEYdJZfRKWXf5AyPk/2jncA84DmfxzrjhCZ4Mm/PE= maunium.net/go/mautrix v0.27.1-0.20260513120123-5fba7e3afae4 h1:zNC9eVAhw8FhKpM3AxNAh/iy75UEYX91uJUvqqAYlvo=
maunium.net/go/mautrix v0.26.5-0.20260410220226-744570e6f1f5/go.mod h1:MX4DQLiBe0c7sI/wizruqdxHinSOWs42/DYsP9GH7Q4= maunium.net/go/mautrix v0.27.1-0.20260513120123-5fba7e3afae4/go.mod h1:3sOGhXi3P1V6/NruTA0gujkvTypXVUraWktCuTGyDuM=

View file

@ -38,7 +38,7 @@ func supportedIfFFmpeg() event.CapabilitySupportLevel {
} }
func capID() string { func capID() string {
base := "fi.mau.signal.capabilities.2025_12_09" base := "fi.mau.signal.capabilities.2026_05_12"
if ffmpeg.Supported() { if ffmpeg.Supported() {
return base + "+ffmpeg" return base + "+ffmpeg"
} }
@ -111,7 +111,8 @@ var signalCaps = &event.RoomFeatures{
}, },
event.CapMsgSticker: { event.CapMsgSticker: {
MimeTypes: map[string]event.CapabilitySupportLevel{ MimeTypes: map[string]event.CapabilitySupportLevel{
"image/webp": event.CapLevelFullySupported, // Signal clients will only render static webp, so apng is preferred
"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(),
@ -211,6 +212,7 @@ 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,
@ -235,5 +237,5 @@ func (s *SignalConnector) GetCapabilities() *bridgev2.NetworkGeneralCapabilities
} }
func (s *SignalConnector) GetBridgeInfoVersion() (info, capabilities int) { func (s *SignalConnector) GetBridgeInfoVersion() (info, capabilities int) {
return 1, 7 return 1, 8
} }

View file

@ -27,6 +27,7 @@ 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"
@ -46,6 +47,7 @@ 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{
@ -76,6 +78,14 @@ 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,7 +4,6 @@ import (
"context" "context"
"encoding/base64" "encoding/base64"
"fmt" "fmt"
"io"
"os" "os"
"maunium.net/go/mautrix/bridgev2" "maunium.net/go/mautrix/bridgev2"
@ -30,6 +29,7 @@ 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,18 +76,11 @@ 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)
} }
return &mediaproxy.GetMediaResponseCallback{ rawDataResp, err = client.Client.DownloadGroupAvatar(ctx, info.GroupAvatarPath, groupMasterKey)
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 0, err return nil, 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).
@ -111,19 +104,27 @@ 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")
} }
return &mediaproxy.GetMediaResponseCallback{ rawDataResp, err = client.Client.DownloadUserAvatar(ctx, info.ProfileAvatarPath, *profileKey)
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 0, err return nil, err
} }
case *signalid.DirectMediaSticker:
log.Info().
Hex("pack_id", info.PackID).
Uint32("sticker_id", info.StickerID).
Msg("Direct downloading sticker")
_, err = w.Write(data) rawDataResp, err = signalmeow.DownloadStickerPackItem(ctx, info.PackID, info.PackKey, info.StickerID)
return int64(len(data)), err if err != nil {
}, log.Err(err).Msg("Direct download failed")
}, nil return nil, err
}
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

@ -137,7 +137,7 @@ func (s *SignalClient) doSendMessage(
} }
msgID := signalid.MakeMessageID(s.Client.Store.ACI, ts) msgID := signalid.MakeMessageID(s.Client.Store.ACI, ts)
msg.AddPendingToIgnore(networkid.TransactionID(msgID)) msg.AddPendingToIgnore(networkid.TransactionID(msgID))
err := s.sendMessage(ctx, msg.Portal.ID, &signalpb.Content{DataMessage: converted}) err := s.sendMessage(ctx, msg.Portal.ID, signalmeow.WrapDataMessage(converted))
if err != nil { if err != nil {
return nil, bridgev2.WrapErrorInStatus(err).WithSendNotice(true) return nil, bridgev2.WrapErrorInStatus(err).WithSendNotice(true)
} }
@ -173,10 +173,10 @@ func (s *SignalClient) HandleMatrixEdit(ctx context.Context, msg *bridgev2.Matri
} }
ts := getTimestampForEvent(msg.InputTransactionID, msg.Event, msg.OrigSender) ts := getTimestampForEvent(msg.InputTransactionID, msg.Event, msg.OrigSender)
converted.Timestamp = &ts converted.Timestamp = &ts
err = s.sendMessage(ctx, msg.Portal.ID, &signalpb.Content{EditMessage: &signalpb.EditMessage{ err = s.sendMessage(ctx, msg.Portal.ID, signalmeow.WrapEditMessage(&signalpb.EditMessage{
TargetSentTimestamp: proto.Uint64(targetSentTimestamp), TargetSentTimestamp: proto.Uint64(targetSentTimestamp),
DataMessage: converted, DataMessage: converted,
}}) }))
if err != nil { if err != nil {
return bridgev2.WrapErrorInStatus(err).WithSendNotice(true) return bridgev2.WrapErrorInStatus(err).WithSendNotice(true)
} }
@ -200,8 +200,7 @@ func (s *SignalClient) HandleMatrixReaction(ctx context.Context, msg *bridgev2.M
return nil, fmt.Errorf("failed to parse target message ID: %w", err) return nil, fmt.Errorf("failed to parse target message ID: %w", err)
} }
ts := getTimestampForEvent(msg.InputTransactionID, msg.Event, msg.OrigSender) ts := getTimestampForEvent(msg.InputTransactionID, msg.Event, msg.OrigSender)
wrappedContent := &signalpb.Content{ err = s.sendMessage(ctx, msg.Portal.ID, signalmeow.WrapDataMessage(&signalpb.DataMessage{
DataMessage: &signalpb.DataMessage{
Timestamp: proto.Uint64(ts), Timestamp: proto.Uint64(ts),
RequiredProtocolVersion: proto.Uint32(uint32(signalpb.DataMessage_REACTIONS)), RequiredProtocolVersion: proto.Uint32(uint32(signalpb.DataMessage_REACTIONS)),
Reaction: &signalpb.DataMessage_Reaction{ Reaction: &signalpb.DataMessage_Reaction{
@ -210,9 +209,7 @@ func (s *SignalClient) HandleMatrixReaction(ctx context.Context, msg *bridgev2.M
TargetAuthorAciBinary: targetAuthorACI[:], TargetAuthorAciBinary: targetAuthorACI[:],
TargetSentTimestamp: proto.Uint64(targetSentTimestamp), TargetSentTimestamp: proto.Uint64(targetSentTimestamp),
}, },
}, }))
}
err = s.sendMessage(ctx, msg.Portal.ID, wrappedContent)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -225,8 +222,7 @@ func (s *SignalClient) HandleMatrixReactionRemove(ctx context.Context, msg *brid
return fmt.Errorf("failed to parse target message ID: %w", err) return fmt.Errorf("failed to parse target message ID: %w", err)
} }
ts := getTimestampForEvent(msg.InputTransactionID, msg.Event, msg.OrigSender) ts := getTimestampForEvent(msg.InputTransactionID, msg.Event, msg.OrigSender)
wrappedContent := &signalpb.Content{ err = s.sendMessage(ctx, msg.Portal.ID, signalmeow.WrapDataMessage(&signalpb.DataMessage{
DataMessage: &signalpb.DataMessage{
Timestamp: proto.Uint64(ts), Timestamp: proto.Uint64(ts),
RequiredProtocolVersion: proto.Uint32(uint32(signalpb.DataMessage_REACTIONS)), RequiredProtocolVersion: proto.Uint32(uint32(signalpb.DataMessage_REACTIONS)),
Reaction: &signalpb.DataMessage_Reaction{ Reaction: &signalpb.DataMessage_Reaction{
@ -235,9 +231,7 @@ func (s *SignalClient) HandleMatrixReactionRemove(ctx context.Context, msg *brid
TargetAuthorAciBinary: targetAuthorACI[:], TargetAuthorAciBinary: targetAuthorACI[:],
TargetSentTimestamp: proto.Uint64(targetSentTimestamp), TargetSentTimestamp: proto.Uint64(targetSentTimestamp),
}, },
}, }))
}
err = s.sendMessage(ctx, msg.Portal.ID, wrappedContent)
if err != nil { if err != nil {
return err return err
} }
@ -252,15 +246,12 @@ func (s *SignalClient) HandleMatrixMessageRemove(ctx context.Context, msg *bridg
return fmt.Errorf("cannot delete other people's messages") return fmt.Errorf("cannot delete other people's messages")
} }
ts := getTimestampForEvent(msg.InputTransactionID, msg.Event, msg.OrigSender) ts := getTimestampForEvent(msg.InputTransactionID, msg.Event, msg.OrigSender)
wrappedContent := &signalpb.Content{ err = s.sendMessage(ctx, msg.Portal.ID, signalmeow.WrapDataMessage(&signalpb.DataMessage{
DataMessage: &signalpb.DataMessage{
Timestamp: proto.Uint64(ts), Timestamp: proto.Uint64(ts),
Delete: &signalpb.DataMessage_Delete{ Delete: &signalpb.DataMessage_Delete{
TargetSentTimestamp: proto.Uint64(targetSentTimestamp), TargetSentTimestamp: proto.Uint64(targetSentTimestamp),
}, },
}, }))
}
err = s.sendMessage(ctx, msg.Portal.ID, wrappedContent)
if err != nil { if err != nil {
return err return err
} }
@ -688,13 +679,11 @@ func (s *SignalClient) HandleMatrixDisappearingTimer(ctx context.Context, msg *b
}) })
} else { } else {
ts := getTimestampForEvent(msg.InputTransactionID, msg.Event, msg.OrigSender) ts := getTimestampForEvent(msg.InputTransactionID, msg.Event, msg.OrigSender)
res := s.Client.SendMessage(ctx, userID, &signalpb.Content{ res := s.Client.SendMessage(ctx, userID, signalmeow.WrapDataMessage(&signalpb.DataMessage{
DataMessage: &signalpb.DataMessage{
Timestamp: ptr.Ptr(ts), Timestamp: ptr.Ptr(ts),
Flags: ptr.Ptr(uint32(signalpb.DataMessage_EXPIRATION_TIMER_UPDATE)), Flags: ptr.Ptr(uint32(signalpb.DataMessage_EXPIRATION_TIMER_UPDATE)),
ExpireTimer: ptr.Ptr(uint32(msg.Content.Timer.Seconds())), ExpireTimer: ptr.Ptr(uint32(msg.Content.Timer.Seconds())),
}, }))
})
if !res.WasSuccessful { if !res.WasSuccessful {
return false, res.Error return false, res.Error
} }
@ -773,8 +762,8 @@ func (s *SignalClient) HandleMatrixDeleteChat(ctx context.Context, msg *bridgev2
recipientID := s.Client.Store.ACIServiceID() recipientID := s.Client.Store.ACIServiceID()
// Send DeleteForMe sync message to self // Send DeleteForMe sync message to self
result := s.Client.SendMessage(ctx, recipientID, &signalpb.Content{ result := s.Client.SendMessage(ctx, recipientID, signalmeow.WrapSyncMessage(&signalpb.SyncMessage{
SyncMessage: &signalpb.SyncMessage{ Content: &signalpb.SyncMessage_DeleteForMe_{
DeleteForMe: &signalpb.SyncMessage_DeleteForMe{ DeleteForMe: &signalpb.SyncMessage_DeleteForMe{
ConversationDeletes: []*signalpb.SyncMessage_DeleteForMe_ConversationDelete{{ ConversationDeletes: []*signalpb.SyncMessage_DeleteForMe_ConversationDelete{{
Conversation: conversationID, Conversation: conversationID,
@ -783,7 +772,7 @@ func (s *SignalClient) HandleMatrixDeleteChat(ctx context.Context, msg *bridgev2
}}, }},
}, },
}, },
}) }))
zerolog.Ctx(ctx).Debug(). zerolog.Ctx(ctx).Debug().
Str("portal_id", string(msg.Portal.ID)). Str("portal_id", string(msg.Portal.ID)).
@ -868,11 +857,11 @@ func (s *SignalClient) syncMessageRequestResponse(
} else { } else {
return fmt.Errorf("invalid portal ID for message request response: %s", portal.ID) return fmt.Errorf("invalid portal ID for message request response: %s", portal.ID)
} }
res := s.Client.SendMessage(ctx, libsignalgo.NewACIServiceID(s.Client.Store.ACI), &signalpb.Content{ res := s.Client.SendMessage(ctx, libsignalgo.NewACIServiceID(s.Client.Store.ACI), signalmeow.WrapSyncMessage(&signalpb.SyncMessage{
SyncMessage: &signalpb.SyncMessage{ Content: &signalpb.SyncMessage_MessageRequestResponse_{
MessageRequestResponse: accept, MessageRequestResponse: accept,
}, },
}) }))
if !res.WasSuccessful { if !res.WasSuccessful {
return res.Error return res.Error
} }
@ -905,13 +894,13 @@ func (s *SignalClient) HandleMatrixAcceptMessageRequest(ctx context.Context, msg
} }
} }
res := s.Client.SendMessage(ctx, userID, &signalpb.Content{ res := s.Client.SendMessage(ctx, userID, &signalpb.Content{
DataMessage: &signalpb.DataMessage{ Content: &signalpb.Content_DataMessage{DataMessage: &signalpb.DataMessage{
Flags: proto.Uint32(uint32(signalpb.DataMessage_PROFILE_KEY_UPDATE)), Flags: proto.Uint32(uint32(signalpb.DataMessage_PROFILE_KEY_UPDATE)),
ProfileKey: profileKey.Slice(), ProfileKey: profileKey.Slice(),
Timestamp: proto.Uint64(getTimestampForEvent(msg.InputTransactionID, msg.Event, msg.OrigSender)), Timestamp: proto.Uint64(getTimestampForEvent(msg.InputTransactionID, msg.Event, msg.OrigSender)),
RequiredProtocolVersion: proto.Uint32(0), RequiredProtocolVersion: proto.Uint32(0),
}, }},
PniSignatureMessage: pniSig, PniSignatureMessage: pniSig,
}) })
if !res.WasSuccessful { if !res.WasSuccessful {

View file

@ -184,7 +184,7 @@ func (evt *Bv2ChatEvent) GetType() bridgev2.RemoteEventType {
return bridgev2.RemoteEventReactionRemove return bridgev2.RemoteEventReactionRemove
} }
return bridgev2.RemoteEventReaction return bridgev2.RemoteEventReaction
case innerEvt.Delete != nil: case innerEvt.Delete != nil, innerEvt.AdminDelete != nil:
return bridgev2.RemoteEventMessageRemove return bridgev2.RemoteEventMessageRemove
case innerEvt.GetGroupV2().GetGroupChange() != nil: case innerEvt.GetGroupV2().GetGroupChange() != nil:
return bridgev2.RemoteEventChatInfoChange return bridgev2.RemoteEventChatInfoChange
@ -303,6 +303,11 @@ func (evt *Bv2ChatEvent) GetTargetMessage() networkid.MessageID {
targetSentTS = innerEvt.Reaction.GetTargetSentTimestamp() targetSentTS = innerEvt.Reaction.GetTargetSentTimestamp()
case innerEvt.Delete != nil: case innerEvt.Delete != nil:
targetSentTS = innerEvt.Delete.GetTargetSentTimestamp() targetSentTS = innerEvt.Delete.GetTargetSentTimestamp()
case innerEvt.AdminDelete != nil:
if len(innerEvt.AdminDelete.GetTargetAuthorAciBinary()) == 16 {
targetAuthorACI = uuid.UUID(innerEvt.AdminDelete.GetTargetAuthorAciBinary())
}
targetSentTS = innerEvt.AdminDelete.GetTargetSentTimestamp()
default: default:
return "" return ""
} }
@ -421,7 +426,7 @@ func (b *Bv2Receipt) GetReadUpTo() time.Time {
return time.Time{} return time.Time{}
} }
var _ bridgev2.RemoteReceipt = (*Bv2Receipt)(nil) var _ bridgev2.RemoteReadReceipt = (*Bv2Receipt)(nil)
func convertReceipts[T any](ctx context.Context, input []T, getMessageFunc func(ctx context.Context, msgID T) (*database.Message, error)) map[networkid.PortalKey]*Bv2Receipt { func convertReceipts[T any](ctx context.Context, input []T, getMessageFunc func(ctx context.Context, msgID T) (*database.Message, error)) map[networkid.PortalKey]*Bv2Receipt {
log := zerolog.Ctx(ctx) log := zerolog.Ctx(ctx)

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.SignalFfiBridgeIdentityKeyStoreGetLocalIdentityKeyPair(C.signal_get_identity_key_pair_callback), get_local_identity_key_pair: C.SignalFfiIdentityKeyStoreGetLocalIdentityKeyPair(C.signal_get_identity_key_pair_callback),
get_local_registration_id: C.SignalFfiBridgeIdentityKeyStoreGetLocalRegistrationId(C.signal_get_local_registration_id_callback), get_local_registration_id: C.SignalFfiIdentityKeyStoreGetLocalRegistrationId(C.signal_get_local_registration_id_callback),
get_identity_key: C.SignalFfiBridgeIdentityKeyStoreGetIdentityKey(C.signal_get_identity_key_callback), get_identity_key: C.SignalFfiIdentityKeyStoreGetIdentityKey(C.signal_get_identity_key_callback),
save_identity_key: C.SignalFfiBridgeIdentityKeyStoreSaveIdentityKey(C.signal_save_identity_key_callback), save_identity_key: C.SignalFfiIdentityKeyStoreSaveIdentityKey(C.signal_save_identity_key_callback),
is_trusted_identity: C.SignalFfiBridgeIdentityKeyStoreIsTrustedIdentity(C.signal_is_trusted_identity_callback), is_trusted_identity: C.SignalFfiIdentityKeyStoreIsTrustedIdentity(C.signal_is_trusted_identity_callback),
destroy: C.SignalFfiBridgeIdentityKeyStoreDestroy(C.signal_destroy_identity_key_store_callback), destroy: C.SignalFfiIdentityKeyStoreDestroy(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.SignalFfiBridgeKyberPreKeyStoreLoadKyberPreKey(C.signal_load_kyber_pre_key_callback), load_kyber_pre_key: C.SignalFfiKyberPreKeyStoreLoadKyberPreKey(C.signal_load_kyber_pre_key_callback),
store_kyber_pre_key: C.SignalFfiBridgeKyberPreKeyStoreStoreKyberPreKey(C.signal_store_kyber_pre_key_callback), store_kyber_pre_key: C.SignalFfiKyberPreKeyStoreStoreKyberPreKey(C.signal_store_kyber_pre_key_callback),
mark_kyber_pre_key_used: C.SignalFfiBridgeKyberPreKeyStoreMarkKyberPreKeyUsed(C.signal_mark_kyber_pre_key_used_callback), mark_kyber_pre_key_used: C.SignalFfiKyberPreKeyStoreMarkKyberPreKeyUsed(C.signal_mark_kyber_pre_key_used_callback),
destroy: C.SignalFfiBridgeKyberPreKeyStoreDestroy(C.signal_destroy_kyber_pre_key_store_callback), destroy: C.SignalFfiKyberPreKeyStoreDestroy(C.signal_destroy_kyber_pre_key_store_callback),
}} }}
} }

@ -1 +1 @@
Subproject commit a5e76674882a89bac1ed3f4a982120652966d21e Subproject commit bbc16886cae2feab1cd1fe271ccc651e8860ce96

View file

@ -261,6 +261,7 @@ typedef enum {
SignalErrorCodeRequestUnauthorized = 220, SignalErrorCodeRequestUnauthorized = 220,
SignalErrorCodeMismatchedDevices = 221, SignalErrorCodeMismatchedDevices = 221,
SignalErrorCodeServiceIdNotFound = 222, SignalErrorCodeServiceIdNotFound = 222,
SignalErrorCodeUploadTooLarge = 223,
} SignalErrorCode; } SignalErrorCode;
enum SignalSvr2CredentialsResult { enum SignalSvr2CredentialsResult {
@ -511,6 +512,46 @@ typedef struct {
const SignalAuthenticatedChatConnection *raw; const SignalAuthenticatedChatConnection *raw;
} SignalConstPointerAuthenticatedChatConnection; } SignalConstPointerAuthenticatedChatConnection;
/**
* A type alias to be used with [`OwnedBufferOf`], so that `OwnedBufferOf<c_char>` and
* `OwnedBufferOf<*const c_char>` get distinct names.
*/
typedef const char *SignalCStringPtr;
/**
* A representation of a array allocated on the Rust heap for use in C code.
*/
typedef struct {
SignalCStringPtr *base;
/**
* The number of elements in the buffer (not necessarily the number of bytes).
*/
size_t length;
} SignalOwnedBufferOfCStringPtr;
typedef struct {
uint32_t cdn;
SignalCStringPtr key;
SignalOwnedBufferOfCStringPtr header_keys;
SignalOwnedBufferOfCStringPtr header_values;
SignalCStringPtr signed_upload_url;
} SignalFfiUploadForm;
/**
* A C callback used to report the results of Rust futures.
*
* cbindgen will produce independent C types like `SignalCPromisei32` and
* `SignalCPromiseProtocolAddress`.
*
* This derives Copy because it behaves like a C type; nevertheless, a promise should still only be
* completed once.
*/
typedef struct {
void (*complete)(SignalFfiError *error, const SignalFfiUploadForm *result, const void *context);
const void *context;
SignalCancellationId cancellation_id;
} SignalCPromiseFfiUploadForm;
typedef SignalConnectionInfo SignalChatConnectionInfo; typedef SignalConnectionInfo SignalChatConnectionInfo;
typedef struct { typedef struct {
@ -562,23 +603,6 @@ typedef struct {
const SignalFfiChatListenerStruct *raw; const SignalFfiChatListenerStruct *raw;
} SignalConstPointerFfiChatListenerStruct; } SignalConstPointerFfiChatListenerStruct;
/**
* A type alias to be used with [`OwnedBufferOf`], so that `OwnedBufferOf<c_char>` and
* `OwnedBufferOf<*const c_char>` get distinct names.
*/
typedef const char *SignalCStringPtr;
/**
* A representation of a array allocated on the Rust heap for use in C code.
*/
typedef struct {
SignalCStringPtr *base;
/**
* The number of elements in the buffer (not necessarily the number of bytes).
*/
size_t length;
} SignalOwnedBufferOfCStringPtr;
typedef struct { typedef struct {
uint16_t status; uint16_t status;
const char *message; const char *message;
@ -605,13 +629,6 @@ typedef struct {
const SignalHttpRequest *raw; const SignalHttpRequest *raw;
} SignalConstPointerHttpRequest; } SignalConstPointerHttpRequest;
/**
* A wrapper type for raw UUIDs, because C treats arrays specially in argument position.
*/
typedef struct {
uint8_t bytes[16];
} SignalUuid;
/** /**
* The fixed-width binary representation of a ServiceId. * The fixed-width binary representation of a ServiceId.
* *
@ -619,6 +636,27 @@ typedef struct {
*/ */
typedef uint8_t SignalServiceIdFixedWidthBinaryBytes[17]; 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.
*/
typedef struct {
uint8_t bytes[16];
} SignalUuid;
typedef struct { typedef struct {
SignalPrivateKey *raw; SignalPrivateKey *raw;
} SignalMutPointerPrivateKey; } SignalMutPointerPrivateKey;
@ -730,10 +768,6 @@ 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;
@ -758,20 +792,18 @@ typedef struct {
SignalSessionRecord *raw; SignalSessionRecord *raw;
} SignalMutPointerSessionRecord; } SignalMutPointerSessionRecord;
typedef int (*SignalFfiBridgeSessionStoreLoadSession)(void *ctx, SignalMutPointerSessionRecord *out, SignalMutPointerProtocolAddress address); typedef int (*SignalFfiSessionStoreLoadSession)(void *ctx, SignalMutPointerSessionRecord *out, SignalMutPointerProtocolAddress address);
typedef int (*SignalFfiBridgeSessionStoreStoreSession)(void *ctx, SignalMutPointerProtocolAddress address, SignalMutPointerSessionRecord record); typedef int (*SignalFfiSessionStoreStoreSession)(void *ctx, SignalMutPointerProtocolAddress address, SignalMutPointerSessionRecord record);
typedef void (*SignalFfiBridgeSessionStoreDestroy)(void *ctx); typedef void (*SignalFfiSessionStoreDestroy)(void *ctx);
typedef struct { typedef struct {
void *ctx; void *ctx;
SignalFfiBridgeSessionStoreLoadSession load_session; SignalFfiSessionStoreLoadSession load_session;
SignalFfiBridgeSessionStoreStoreSession store_session; SignalFfiSessionStoreStoreSession store_session;
SignalFfiBridgeSessionStoreDestroy destroy; SignalFfiSessionStoreDestroy destroy;
} SignalFfiBridgeSessionStoreStruct; } SignalSessionStore;
typedef SignalFfiBridgeSessionStoreStruct SignalSessionStore;
typedef struct { typedef struct {
const SignalSessionStore *raw; const SignalSessionStore *raw;
@ -786,29 +818,27 @@ typedef struct {
SignalMutPointerPublicKey second; SignalMutPointerPublicKey second;
} SignalPairOfMutPointerPrivateKeyMutPointerPublicKey; } SignalPairOfMutPointerPrivateKeyMutPointerPublicKey;
typedef int (*SignalFfiBridgeIdentityKeyStoreGetLocalIdentityKeyPair)(void *ctx, SignalPairOfMutPointerPrivateKeyMutPointerPublicKey *out); typedef int (*SignalFfiIdentityKeyStoreGetLocalIdentityKeyPair)(void *ctx, SignalPairOfMutPointerPrivateKeyMutPointerPublicKey *out);
typedef int (*SignalFfiBridgeIdentityKeyStoreGetLocalRegistrationId)(void *ctx, uint32_t *out); typedef int (*SignalFfiIdentityKeyStoreGetLocalRegistrationId)(void *ctx, uint32_t *out);
typedef int (*SignalFfiBridgeIdentityKeyStoreGetIdentityKey)(void *ctx, SignalMutPointerPublicKey *out, SignalMutPointerProtocolAddress address); typedef int (*SignalFfiIdentityKeyStoreGetIdentityKey)(void *ctx, SignalMutPointerPublicKey *out, SignalMutPointerProtocolAddress address);
typedef int (*SignalFfiBridgeIdentityKeyStoreSaveIdentityKey)(void *ctx, uint8_t *out, SignalMutPointerProtocolAddress address, SignalMutPointerPublicKey public_key); typedef int (*SignalFfiIdentityKeyStoreSaveIdentityKey)(void *ctx, uint8_t *out, SignalMutPointerProtocolAddress address, SignalMutPointerPublicKey public_key);
typedef int (*SignalFfiBridgeIdentityKeyStoreIsTrustedIdentity)(void *ctx, bool *out, SignalMutPointerProtocolAddress address, SignalMutPointerPublicKey public_key, uint32_t direction); typedef int (*SignalFfiIdentityKeyStoreIsTrustedIdentity)(void *ctx, bool *out, SignalMutPointerProtocolAddress address, SignalMutPointerPublicKey public_key, uint32_t direction);
typedef void (*SignalFfiBridgeIdentityKeyStoreDestroy)(void *ctx); typedef void (*SignalFfiIdentityKeyStoreDestroy)(void *ctx);
typedef struct { typedef struct {
void *ctx; void *ctx;
SignalFfiBridgeIdentityKeyStoreGetLocalIdentityKeyPair get_local_identity_key_pair; SignalFfiIdentityKeyStoreGetLocalIdentityKeyPair get_local_identity_key_pair;
SignalFfiBridgeIdentityKeyStoreGetLocalRegistrationId get_local_registration_id; SignalFfiIdentityKeyStoreGetLocalRegistrationId get_local_registration_id;
SignalFfiBridgeIdentityKeyStoreGetIdentityKey get_identity_key; SignalFfiIdentityKeyStoreGetIdentityKey get_identity_key;
SignalFfiBridgeIdentityKeyStoreSaveIdentityKey save_identity_key; SignalFfiIdentityKeyStoreSaveIdentityKey save_identity_key;
SignalFfiBridgeIdentityKeyStoreIsTrustedIdentity is_trusted_identity; SignalFfiIdentityKeyStoreIsTrustedIdentity is_trusted_identity;
SignalFfiBridgeIdentityKeyStoreDestroy destroy; SignalFfiIdentityKeyStoreDestroy destroy;
} SignalFfiBridgeIdentityKeyStoreStruct; } SignalIdentityKeyStore;
typedef SignalFfiBridgeIdentityKeyStoreStruct SignalIdentityKeyStore;
typedef struct { typedef struct {
const SignalIdentityKeyStore *raw; const SignalIdentityKeyStore *raw;
@ -822,23 +852,21 @@ typedef struct {
SignalPreKeyRecord *raw; SignalPreKeyRecord *raw;
} SignalMutPointerPreKeyRecord; } SignalMutPointerPreKeyRecord;
typedef int (*SignalFfiBridgePreKeyStoreLoadPreKey)(void *ctx, SignalMutPointerPreKeyRecord *out, uint32_t id); typedef int (*SignalFfiPreKeyStoreLoadPreKey)(void *ctx, SignalMutPointerPreKeyRecord *out, uint32_t id);
typedef int (*SignalFfiBridgePreKeyStoreStorePreKey)(void *ctx, uint32_t id, SignalMutPointerPreKeyRecord record); typedef int (*SignalFfiPreKeyStoreStorePreKey)(void *ctx, uint32_t id, SignalMutPointerPreKeyRecord record);
typedef int (*SignalFfiBridgePreKeyStoreRemovePreKey)(void *ctx, uint32_t id); typedef int (*SignalFfiPreKeyStoreRemovePreKey)(void *ctx, uint32_t id);
typedef void (*SignalFfiBridgePreKeyStoreDestroy)(void *ctx); typedef void (*SignalFfiPreKeyStoreDestroy)(void *ctx);
typedef struct { typedef struct {
void *ctx; void *ctx;
SignalFfiBridgePreKeyStoreLoadPreKey load_pre_key; SignalFfiPreKeyStoreLoadPreKey load_pre_key;
SignalFfiBridgePreKeyStoreStorePreKey store_pre_key; SignalFfiPreKeyStoreStorePreKey store_pre_key;
SignalFfiBridgePreKeyStoreRemovePreKey remove_pre_key; SignalFfiPreKeyStoreRemovePreKey remove_pre_key;
SignalFfiBridgePreKeyStoreDestroy destroy; SignalFfiPreKeyStoreDestroy destroy;
} SignalFfiBridgePreKeyStoreStruct; } SignalPreKeyStore;
typedef SignalFfiBridgePreKeyStoreStruct SignalPreKeyStore;
typedef struct { typedef struct {
const SignalPreKeyStore *raw; const SignalPreKeyStore *raw;
@ -848,20 +876,18 @@ typedef struct {
SignalSignedPreKeyRecord *raw; SignalSignedPreKeyRecord *raw;
} SignalMutPointerSignedPreKeyRecord; } SignalMutPointerSignedPreKeyRecord;
typedef int (*SignalFfiBridgeSignedPreKeyStoreLoadSignedPreKey)(void *ctx, SignalMutPointerSignedPreKeyRecord *out, uint32_t id); typedef int (*SignalFfiSignedPreKeyStoreLoadSignedPreKey)(void *ctx, SignalMutPointerSignedPreKeyRecord *out, uint32_t id);
typedef int (*SignalFfiBridgeSignedPreKeyStoreStoreSignedPreKey)(void *ctx, uint32_t id, SignalMutPointerSignedPreKeyRecord record); typedef int (*SignalFfiSignedPreKeyStoreStoreSignedPreKey)(void *ctx, uint32_t id, SignalMutPointerSignedPreKeyRecord record);
typedef void (*SignalFfiBridgeSignedPreKeyStoreDestroy)(void *ctx); typedef void (*SignalFfiSignedPreKeyStoreDestroy)(void *ctx);
typedef struct { typedef struct {
void *ctx; void *ctx;
SignalFfiBridgeSignedPreKeyStoreLoadSignedPreKey load_signed_pre_key; SignalFfiSignedPreKeyStoreLoadSignedPreKey load_signed_pre_key;
SignalFfiBridgeSignedPreKeyStoreStoreSignedPreKey store_signed_pre_key; SignalFfiSignedPreKeyStoreStoreSignedPreKey store_signed_pre_key;
SignalFfiBridgeSignedPreKeyStoreDestroy destroy; SignalFfiSignedPreKeyStoreDestroy destroy;
} SignalFfiBridgeSignedPreKeyStoreStruct; } SignalSignedPreKeyStore;
typedef SignalFfiBridgeSignedPreKeyStoreStruct SignalSignedPreKeyStore;
typedef struct { typedef struct {
const SignalSignedPreKeyStore *raw; const SignalSignedPreKeyStore *raw;
@ -871,23 +897,21 @@ typedef struct {
SignalKyberPreKeyRecord *raw; SignalKyberPreKeyRecord *raw;
} SignalMutPointerKyberPreKeyRecord; } SignalMutPointerKyberPreKeyRecord;
typedef int (*SignalFfiBridgeKyberPreKeyStoreLoadKyberPreKey)(void *ctx, SignalMutPointerKyberPreKeyRecord *out, uint32_t id); typedef int (*SignalFfiKyberPreKeyStoreLoadKyberPreKey)(void *ctx, SignalMutPointerKyberPreKeyRecord *out, uint32_t id);
typedef int (*SignalFfiBridgeKyberPreKeyStoreStoreKyberPreKey)(void *ctx, uint32_t id, SignalMutPointerKyberPreKeyRecord record); typedef int (*SignalFfiKyberPreKeyStoreStoreKyberPreKey)(void *ctx, uint32_t id, SignalMutPointerKyberPreKeyRecord record);
typedef int (*SignalFfiBridgeKyberPreKeyStoreMarkKyberPreKeyUsed)(void *ctx, uint32_t id, uint32_t ec_prekey_id, SignalMutPointerPublicKey base_key); typedef int (*SignalFfiKyberPreKeyStoreMarkKyberPreKeyUsed)(void *ctx, uint32_t id, uint32_t ec_prekey_id, SignalMutPointerPublicKey base_key);
typedef void (*SignalFfiBridgeKyberPreKeyStoreDestroy)(void *ctx); typedef void (*SignalFfiKyberPreKeyStoreDestroy)(void *ctx);
typedef struct { typedef struct {
void *ctx; void *ctx;
SignalFfiBridgeKyberPreKeyStoreLoadKyberPreKey load_kyber_pre_key; SignalFfiKyberPreKeyStoreLoadKyberPreKey load_kyber_pre_key;
SignalFfiBridgeKyberPreKeyStoreStoreKyberPreKey store_kyber_pre_key; SignalFfiKyberPreKeyStoreStoreKyberPreKey store_kyber_pre_key;
SignalFfiBridgeKyberPreKeyStoreMarkKyberPreKeyUsed mark_kyber_pre_key_used; SignalFfiKyberPreKeyStoreMarkKyberPreKeyUsed mark_kyber_pre_key_used;
SignalFfiBridgeKyberPreKeyStoreDestroy destroy; SignalFfiKyberPreKeyStoreDestroy destroy;
} SignalFfiBridgeKyberPreKeyStoreStruct; } SignalKyberPreKeyStore;
typedef SignalFfiBridgeKyberPreKeyStoreStruct SignalKyberPreKeyStore;
typedef struct { typedef struct {
const SignalKyberPreKeyStore *raw; const SignalKyberPreKeyStore *raw;
@ -945,6 +969,11 @@ typedef struct {
SignalOwnedBuffer second; SignalOwnedBuffer second;
} SignalPairOfc_charOwnedBufferOfc_uchar; } SignalPairOfc_charOwnedBufferOfc_uchar;
typedef struct {
SignalPairOfc_charOwnedBufferOfc_uchar first;
int64_t second;
} SignalPairOfPairOfc_charOwnedBufferOfc_uchari64;
typedef struct { typedef struct {
const char *first; const char *first;
bool second; bool second;
@ -1018,20 +1047,18 @@ typedef struct {
SignalSenderKeyRecord *raw; SignalSenderKeyRecord *raw;
} SignalMutPointerSenderKeyRecord; } SignalMutPointerSenderKeyRecord;
typedef int (*SignalFfiBridgeSenderKeyStoreLoadSenderKey)(void *ctx, SignalMutPointerSenderKeyRecord *out, SignalMutPointerProtocolAddress sender, SignalUuid distribution_id); typedef int (*SignalFfiSenderKeyStoreLoadSenderKey)(void *ctx, SignalMutPointerSenderKeyRecord *out, SignalMutPointerProtocolAddress sender, SignalUuid distribution_id);
typedef int (*SignalFfiBridgeSenderKeyStoreStoreSenderKey)(void *ctx, SignalMutPointerProtocolAddress sender, SignalUuid distribution_id, SignalMutPointerSenderKeyRecord record); typedef int (*SignalFfiSenderKeyStoreStoreSenderKey)(void *ctx, SignalMutPointerProtocolAddress sender, SignalUuid distribution_id, SignalMutPointerSenderKeyRecord record);
typedef void (*SignalFfiBridgeSenderKeyStoreDestroy)(void *ctx); typedef void (*SignalFfiSenderKeyStoreDestroy)(void *ctx);
typedef struct { typedef struct {
void *ctx; void *ctx;
SignalFfiBridgeSenderKeyStoreLoadSenderKey load_sender_key; SignalFfiSenderKeyStoreLoadSenderKey load_sender_key;
SignalFfiBridgeSenderKeyStoreStoreSenderKey store_sender_key; SignalFfiSenderKeyStoreStoreSenderKey store_sender_key;
SignalFfiBridgeSenderKeyStoreDestroy destroy; SignalFfiSenderKeyStoreDestroy destroy;
} SignalFfiBridgeSenderKeyStoreStruct; } SignalSenderKeyStore;
typedef SignalFfiBridgeSenderKeyStoreStruct SignalSenderKeyStore;
typedef struct { typedef struct {
const SignalSenderKeyStore *raw; const SignalSenderKeyStore *raw;
@ -1075,15 +1102,23 @@ typedef struct {
SignalIncrementalMac *raw; SignalIncrementalMac *raw;
} SignalMutPointerIncrementalMac; } SignalMutPointerIncrementalMac;
typedef void (*SignalLogCallback)(void *ctx, SignalLogLevel level, const char *file, uint32_t line, const char *message); typedef int (*SignalFfiLoggerLog)(void *ctx, SignalLogLevel level, const char *file, uint32_t line, const char *message);
typedef void (*SignalLogFlushCallback)(void *ctx); typedef int (*SignalFfiLoggerFlush)(void *ctx);
typedef void (*SignalFfiLoggerDestroy)(void *ctx);
typedef struct { typedef struct {
void *ctx; void *ctx;
SignalLogCallback log; SignalFfiLoggerLog log;
SignalLogFlushCallback flush; SignalFfiLoggerFlush flush;
} SignalFfiLogger; SignalFfiLoggerDestroy destroy;
} 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.
@ -1095,10 +1130,10 @@ typedef struct {
* completed once. * completed once.
*/ */
typedef struct { typedef struct {
void (*complete)(SignalFfiError *error, const SignalOwnedBuffer *result, const void *context); void (*complete)(SignalFfiError *error, const SignalPairOfOwnedBufferOfc_ucharOwnedBufferOfc_uchar *result, const void *context);
const void *context; const void *context;
SignalCancellationId cancellation_id; SignalCancellationId cancellation_id;
} SignalCPromiseOwnedBufferOfc_uchar; } SignalCPromisePairOfOwnedBufferOfc_ucharOwnedBufferOfc_uchar;
typedef struct { typedef struct {
const SignalUnauthenticatedChatConnection *raw; const SignalUnauthenticatedChatConnection *raw;
@ -1168,20 +1203,18 @@ typedef struct {
const SignalMessageBackupValidationOutcome *raw; const SignalMessageBackupValidationOutcome *raw;
} SignalConstPointerMessageBackupValidationOutcome; } SignalConstPointerMessageBackupValidationOutcome;
typedef int (*SignalFfiBridgeInputStreamRead)(void *ctx, size_t *out, SignalBorrowedMutableBuffer buf); typedef int (*SignalFfiInputStreamRead)(void *ctx, size_t *out, SignalBorrowedMutableBuffer buf);
typedef int (*SignalFfiBridgeInputStreamSkip)(void *ctx, uint64_t amount); typedef int (*SignalFfiInputStreamSkip)(void *ctx, uint64_t amount);
typedef void (*SignalFfiBridgeInputStreamDestroy)(void *ctx); typedef void (*SignalFfiInputStreamDestroy)(void *ctx);
typedef struct { typedef struct {
void *ctx; void *ctx;
SignalFfiBridgeInputStreamRead read; SignalFfiInputStreamRead read;
SignalFfiBridgeInputStreamSkip skip; SignalFfiInputStreamSkip skip;
SignalFfiBridgeInputStreamDestroy destroy; SignalFfiInputStreamDestroy destroy;
} SignalFfiBridgeInputStreamStruct; } SignalInputStream;
typedef SignalFfiBridgeInputStreamStruct SignalInputStream;
typedef struct { typedef struct {
const SignalInputStream *raw; const SignalInputStream *raw;
@ -1615,9 +1648,7 @@ typedef struct {
SignalValidatingMac *raw; SignalValidatingMac *raw;
} SignalMutPointerValidatingMac; } SignalMutPointerValidatingMac;
typedef SignalFfiBridgeInputStreamStruct SignalFfiBridgeSyncInputStreamStruct; typedef SignalInputStream SignalSyncInputStream;
typedef SignalFfiBridgeSyncInputStreamStruct SignalSyncInputStream;
typedef struct { typedef struct {
const SignalSyncInputStream *raw; const SignalSyncInputStream *raw;
@ -1695,6 +1726,8 @@ SignalFfiError *signal_authenticated_chat_connection_destroy(SignalMutPointerAut
SignalFfiError *signal_authenticated_chat_connection_disconnect(SignalCPromisebool *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerAuthenticatedChatConnection chat); SignalFfiError *signal_authenticated_chat_connection_disconnect(SignalCPromisebool *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerAuthenticatedChatConnection chat);
SignalFfiError *signal_authenticated_chat_connection_get_upload_form(SignalCPromiseFfiUploadForm *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerAuthenticatedChatConnection chat, uint64_t upload_length);
SignalFfiError *signal_authenticated_chat_connection_info(SignalMutPointerChatConnectionInfo *out, SignalConstPointerAuthenticatedChatConnection chat); SignalFfiError *signal_authenticated_chat_connection_info(SignalMutPointerChatConnectionInfo *out, SignalConstPointerAuthenticatedChatConnection chat);
SignalFfiError *signal_authenticated_chat_connection_init_listener(SignalConstPointerAuthenticatedChatConnection chat, SignalConstPointerFfiChatListenerStruct listener); SignalFfiError *signal_authenticated_chat_connection_init_listener(SignalConstPointerAuthenticatedChatConnection chat, SignalConstPointerFfiChatListenerStruct listener);
@ -1703,6 +1736,10 @@ 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);
@ -1863,9 +1900,9 @@ 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, SignalConstPointerFfiSessionStoreStruct session_store, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store); SignalFfiError *signal_decrypt_message(SignalOwnedBuffer *out, SignalConstPointerSignalMessage message, SignalConstPointerProtocolAddress protocol_address, SignalConstPointerProtocolAddress local_address, SignalConstPointerFfiSessionStoreStruct session_store, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store);
SignalFfiError *signal_decrypt_pre_key_message(SignalOwnedBuffer *out, SignalConstPointerPreKeySignalMessage message, SignalConstPointerProtocolAddress protocol_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);
SignalFfiError *signal_decryption_error_message_clone(SignalMutPointerDecryptionErrorMessage *new_obj, SignalConstPointerDecryptionErrorMessage obj); SignalFfiError *signal_decryption_error_message_clone(SignalMutPointerDecryptionErrorMessage *new_obj, SignalConstPointerDecryptionErrorMessage obj);
@ -1891,7 +1928,7 @@ SignalFfiError *signal_device_transfer_generate_private_key(SignalOwnedBuffer *o
SignalFfiError *signal_device_transfer_generate_private_key_with_format(SignalOwnedBuffer *out, uint8_t key_format); SignalFfiError *signal_device_transfer_generate_private_key_with_format(SignalOwnedBuffer *out, uint8_t key_format);
SignalFfiError *signal_encrypt_message(SignalMutPointerCiphertextMessage *out, SignalBorrowedBuffer ptext, SignalConstPointerProtocolAddress protocol_address, SignalConstPointerFfiSessionStoreStruct session_store, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store, uint64_t now); SignalFfiError *signal_encrypt_message(SignalMutPointerCiphertextMessage *out, SignalBorrowedBuffer ptext, SignalConstPointerProtocolAddress protocol_address, SignalConstPointerProtocolAddress local_address, SignalConstPointerFfiSessionStoreStruct session_store, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store, uint64_t now);
void signal_error_free(SignalFfiError *err); void signal_error_free(SignalFfiError *err);
@ -1905,7 +1942,7 @@ SignalFfiError *signal_error_get_mismatched_device_errors(SignalOwnedBufferOfFfi
SignalFfiError *signal_error_get_our_fingerprint_version(uint32_t *out, SignalUnwindSafeArgSignalFfiError err); SignalFfiError *signal_error_get_our_fingerprint_version(uint32_t *out, SignalUnwindSafeArgSignalFfiError err);
SignalFfiError *signal_error_get_rate_limit_challenge(SignalPairOfc_charOwnedBufferOfc_uchar *out, SignalUnwindSafeArgSignalFfiError err); SignalFfiError *signal_error_get_rate_limit_challenge(SignalPairOfPairOfc_charOwnedBufferOfc_uchari64 *out, SignalUnwindSafeArgSignalFfiError err);
SignalFfiError *signal_error_get_registration_error_not_deliverable(SignalPairOfc_charbool *out, SignalUnwindSafeArgSignalFfiError err); SignalFfiError *signal_error_get_registration_error_not_deliverable(SignalPairOfc_charbool *out, SignalUnwindSafeArgSignalFfiError err);
@ -2080,18 +2117,14 @@ SignalFfiError *signal_incremental_mac_initialize(SignalMutPointerIncrementalMac
SignalFfiError *signal_incremental_mac_update(SignalOwnedBuffer *out, SignalMutPointerIncrementalMac mac, SignalBorrowedBuffer bytes, uint32_t offset, uint32_t length); SignalFfiError *signal_incremental_mac_update(SignalOwnedBuffer *out, SignalMutPointerIncrementalMac mac, SignalBorrowedBuffer bytes, uint32_t offset, uint32_t length);
bool signal_init_logger(SignalLogLevel max_level, SignalFfiLogger logger); 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_distinguished(SignalCPromiseOwnedBufferOfc_uchar *promise, SignalConstPointerTokioAsyncContext async_runtime, uint8_t environment, SignalConstPointerUnauthenticatedChatConnection chat_connection, SignalOptionalBorrowedSliceOfc_uchar last_distinguished_tree_head); 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_e164_search_key(SignalOwnedBuffer *out, const char *e164); SignalFfiError *signal_key_transparency_e164_search_key(SignalOwnedBuffer *out, const char *e164);
SignalFfiError *signal_key_transparency_monitor(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_monitor);
SignalFfiError *signal_key_transparency_search(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);
SignalFfiError *signal_key_transparency_username_hash_search_key(SignalOwnedBuffer *out, SignalBorrowedBuffer hash); SignalFfiError *signal_key_transparency_username_hash_search_key(SignalOwnedBuffer *out, SignalBorrowedBuffer hash);
SignalFfiError *signal_kyber_key_pair_clone(SignalMutPointerKyberKeyPair *new_obj, SignalConstPointerKyberKeyPair obj); SignalFfiError *signal_kyber_key_pair_clone(SignalMutPointerKyberKeyPair *new_obj, SignalConstPointerKyberKeyPair obj);
@ -2322,7 +2355,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, SignalConstPointerFfiSessionStoreStruct session_store, SignalConstPointerFfiIdentityKeyStoreStruct identity_key_store, uint64_t now); 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_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);
@ -2724,16 +2757,22 @@ SignalFfiError *signal_tokio_async_context_new(SignalMutPointerTokioAsyncContext
SignalFfiError *signal_unauthenticated_chat_connection_account_exists(SignalCPromisebool *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthenticatedChatConnection chat, const SignalServiceIdFixedWidthBinaryBytes *account); SignalFfiError *signal_unauthenticated_chat_connection_account_exists(SignalCPromisebool *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthenticatedChatConnection chat, const SignalServiceIdFixedWidthBinaryBytes *account);
SignalFfiError *signal_unauthenticated_chat_connection_backup_get_media_upload_form(SignalCPromiseFfiUploadForm *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthenticatedChatConnection chat, SignalBorrowedBuffer credential, SignalBorrowedBuffer server_keys, SignalConstPointerPrivateKey signing_key, uint64_t upload_size, int64_t rng);
SignalFfiError *signal_unauthenticated_chat_connection_backup_get_upload_form(SignalCPromiseFfiUploadForm *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthenticatedChatConnection chat, SignalBorrowedBuffer credential, SignalBorrowedBuffer server_keys, SignalConstPointerPrivateKey signing_key, uint64_t upload_size, int64_t rng);
SignalFfiError *signal_unauthenticated_chat_connection_connect(SignalCPromiseMutPointerUnauthenticatedChatConnection *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerConnectionManager connection_manager, SignalBorrowedBytestringArray languages); SignalFfiError *signal_unauthenticated_chat_connection_connect(SignalCPromiseMutPointerUnauthenticatedChatConnection *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerConnectionManager connection_manager, SignalBorrowedBytestringArray languages);
SignalFfiError *signal_unauthenticated_chat_connection_destroy(SignalMutPointerUnauthenticatedChatConnection p); SignalFfiError *signal_unauthenticated_chat_connection_destroy(SignalMutPointerUnauthenticatedChatConnection p);
SignalFfiError *signal_unauthenticated_chat_connection_disconnect(SignalCPromisebool *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthenticatedChatConnection chat); SignalFfiError *signal_unauthenticated_chat_connection_disconnect(SignalCPromisebool *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthenticatedChatConnection chat);
SignalFfiError *signal_unauthenticated_chat_connection_get_pre_keys_access_group_auth(SignalCPromiseFfiPreKeysResponse *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthenticatedChatConnection chat, SignalBorrowedBuffer auth, const SignalServiceIdFixedWidthBinaryBytes *target, int32_t device);
SignalFfiError *signal_unauthenticated_chat_connection_get_pre_keys_access_key_auth(SignalCPromiseFfiPreKeysResponse *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthenticatedChatConnection chat, const uint8_t (*auth)[16], const SignalServiceIdFixedWidthBinaryBytes *target, int32_t device); SignalFfiError *signal_unauthenticated_chat_connection_get_pre_keys_access_key_auth(SignalCPromiseFfiPreKeysResponse *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthenticatedChatConnection chat, const uint8_t (*auth)[16], const SignalServiceIdFixedWidthBinaryBytes *target, int32_t device);
SignalFfiError *signal_unauthenticated_chat_connection_get_pre_keys_group_auth(SignalCPromiseFfiPreKeysResponse *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthenticatedChatConnection chat, SignalBorrowedBuffer auth, const SignalServiceIdFixedWidthBinaryBytes *target, int32_t device);
SignalFfiError *signal_unauthenticated_chat_connection_get_pre_keys_unrestricted_auth(SignalCPromiseFfiPreKeysResponse *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerUnauthenticatedChatConnection chat, const SignalServiceIdFixedWidthBinaryBytes *target, int32_t device);
SignalFfiError *signal_unauthenticated_chat_connection_info(SignalMutPointerChatConnectionInfo *out, SignalConstPointerUnauthenticatedChatConnection chat); SignalFfiError *signal_unauthenticated_chat_connection_info(SignalMutPointerChatConnectionInfo *out, SignalConstPointerUnauthenticatedChatConnection chat);
SignalFfiError *signal_unauthenticated_chat_connection_init_listener(SignalConstPointerUnauthenticatedChatConnection chat, SignalConstPointerFfiChatListenerStruct listener); SignalFfiError *signal_unauthenticated_chat_connection_init_listener(SignalConstPointerUnauthenticatedChatConnection chat, SignalConstPointerFfiChatListenerStruct listener);
@ -2744,6 +2783,8 @@ 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

@ -21,6 +21,7 @@ package libsignalgo
extern void signal_log_callback(void *ctx, SignalLogLevel level, char *file, uint32_t line, char *message); extern void signal_log_callback(void *ctx, SignalLogLevel level, char *file, uint32_t line, char *message);
extern void signal_log_flush_callback(void *ctx); extern void signal_log_flush_callback(void *ctx);
extern void signal_log_destroy_callback(void *ctx);
*/ */
import "C" import "C"
import ( import (
@ -40,6 +41,11 @@ func signal_log_flush_callback(ctx unsafe.Pointer) {
ffiLogger.Flush() ffiLogger.Flush()
} }
//export signal_log_destroy_callback
func signal_log_destroy_callback(ctx unsafe.Pointer) {
ffiLogger.Destroy()
}
type LogLevel int type LogLevel int
const ( const (
@ -53,12 +59,14 @@ const (
type Logger interface { type Logger interface {
Log(level LogLevel, file string, line uint, message string) Log(level LogLevel, file string, line uint, message string)
Flush() Flush()
Destroy()
} }
func InitLogger(level LogLevel, logger Logger) { func InitLogger(level LogLevel, logger Logger) {
ffiLogger = logger ffiLogger = logger
C.signal_init_logger(C.SignalLogLevel(level), C.SignalFfiLogger{ C.signal_init_logger(C.SignalLogLevel(level), C.SignalFfiLoggerStruct{
log: C.SignalLogCallback(C.signal_log_callback), log: C.SignalFfiLoggerLog(C.signal_log_callback),
flush: C.SignalLogFlushCallback(C.signal_log_flush_callback), flush: C.SignalFfiLoggerFlush(C.signal_log_flush_callback),
destroy: C.SignalFfiLoggerDestroy(C.signal_log_destroy_callback),
}) })
} }

View file

@ -27,7 +27,7 @@ import (
"time" "time"
) )
func Encrypt(ctx context.Context, plaintext []byte, forAddress *Address, sessionStore SessionStore, identityKeyStore IdentityKeyStore) (*CiphertextMessage, error) { func Encrypt(ctx context.Context, plaintext []byte, forAddress, localAddress *Address, sessionStore SessionStore, identityKeyStore IdentityKeyStore) (*CiphertextMessage, error) {
var ciphertextMessage C.SignalMutPointerCiphertextMessage var ciphertextMessage C.SignalMutPointerCiphertextMessage
var now C.uint64_t = C.uint64_t(time.Now().Unix()) var now C.uint64_t = C.uint64_t(time.Now().Unix())
callbackCtx := NewCallbackContext(ctx) callbackCtx := NewCallbackContext(ctx)
@ -36,6 +36,7 @@ func Encrypt(ctx context.Context, plaintext []byte, forAddress *Address, session
&ciphertextMessage, &ciphertextMessage,
BytesToBuffer(plaintext), BytesToBuffer(plaintext),
forAddress.constPtr(), forAddress.constPtr(),
localAddress.constPtr(),
callbackCtx.wrapSessionStore(sessionStore), callbackCtx.wrapSessionStore(sessionStore),
callbackCtx.wrapIdentityKeyStore(identityKeyStore), callbackCtx.wrapIdentityKeyStore(identityKeyStore),
now, now,
@ -48,7 +49,7 @@ func Encrypt(ctx context.Context, plaintext []byte, forAddress *Address, session
return wrapCiphertextMessage(ciphertextMessage.raw), nil return wrapCiphertextMessage(ciphertextMessage.raw), nil
} }
func Decrypt(ctx context.Context, message *Message, fromAddress *Address, sessionStore SessionStore, identityStore IdentityKeyStore) ([]byte, error) { func Decrypt(ctx context.Context, message *Message, fromAddress, localAddress *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{}
@ -56,6 +57,7 @@ func Decrypt(ctx context.Context, message *Message, fromAddress *Address, sessio
&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

@ -26,7 +26,7 @@ import (
"runtime" "runtime"
) )
func DecryptPreKey(ctx context.Context, preKeyMessage *PreKeyMessage, fromAddress *Address, sessionStore SessionStore, identityStore IdentityKeyStore, preKeyStore PreKeyStore, signedPreKeyStore SignedPreKeyStore, kyberPreKeyStore KyberPreKeyStore) ([]byte, error) { func DecryptPreKey(ctx context.Context, preKeyMessage *PreKeyMessage, fromAddress, localAddress *Address, sessionStore SessionStore, identityStore IdentityKeyStore, preKeyStore PreKeyStore, signedPreKeyStore SignedPreKeyStore, kyberPreKeyStore KyberPreKeyStore) ([]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{}
@ -34,6 +34,7 @@ func DecryptPreKey(ctx context.Context, preKeyMessage *PreKeyMessage, fromAddres
&decrypted, &decrypted,
preKeyMessage.constPtr(), preKeyMessage.constPtr(),
fromAddress.constPtr(), fromAddress.constPtr(),
localAddress.constPtr(),
callbackCtx.wrapSessionStore(sessionStore), callbackCtx.wrapSessionStore(sessionStore),
callbackCtx.wrapIdentityKeyStore(identityStore), callbackCtx.wrapIdentityKeyStore(identityStore),
callbackCtx.wrapPreKeyStore(preKeyStore), callbackCtx.wrapPreKeyStore(preKeyStore),

View file

@ -27,13 +27,14 @@ import (
"time" "time"
) )
func ProcessPreKeyBundle(ctx context.Context, bundle *PreKeyBundle, forAddress *Address, sessionStore SessionStore, identityStore IdentityKeyStore) error { func ProcessPreKeyBundle(ctx context.Context, bundle *PreKeyBundle, forAddress, localAddress *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.SignalFfiBridgePreKeyStoreLoadPreKey(C.signal_load_pre_key_callback), load_pre_key: C.SignalFfiPreKeyStoreLoadPreKey(C.signal_load_pre_key_callback),
store_pre_key: C.SignalFfiBridgePreKeyStoreStorePreKey(C.signal_store_pre_key_callback), store_pre_key: C.SignalFfiPreKeyStoreStorePreKey(C.signal_store_pre_key_callback),
remove_pre_key: C.SignalFfiBridgePreKeyStoreRemovePreKey(C.signal_remove_pre_key_callback), remove_pre_key: C.SignalFfiPreKeyStoreRemovePreKey(C.signal_remove_pre_key_callback),
destroy: C.SignalFfiBridgePreKeyStoreDestroy(C.signal_destroy_pre_key_store_callback), destroy: C.SignalFfiPreKeyStoreDestroy(C.signal_destroy_pre_key_store_callback),
}} }}
} }

View file

@ -44,8 +44,17 @@ func NewSealedSenderAddress(e164 string, uuid uuid.UUID, deviceID uint32) *Seale
} }
} }
func SealedSenderEncryptPlaintext(ctx context.Context, message []byte, contentHint UnidentifiedSenderMessageContentHint, forAddress *Address, fromSenderCert *SenderCertificate, sessionStore SessionStore, identityStore IdentityKeyStore, groupID *GroupIdentifier) ([]byte, error) { func SealedSenderEncryptPlaintext(
ciphertextMessage, err := Encrypt(ctx, message, forAddress, sessionStore, identityStore) ctx context.Context,
message []byte,
contentHint UnidentifiedSenderMessageContentHint,
forAddress, localAddress *Address,
fromSenderCert *SenderCertificate,
sessionStore SessionStore,
identityStore IdentityKeyStore,
groupID *GroupIdentifier,
) ([]byte, error) {
ciphertextMessage, err := Encrypt(ctx, message, forAddress, localAddress, sessionStore, identityStore)
if err != nil { if err != nil {
return nil, err return nil, err
} }

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.SignalFfiBridgeSenderKeyStoreLoadSenderKey(C.signal_load_sender_key_callback), load_sender_key: C.SignalFfiSenderKeyStoreLoadSenderKey(C.signal_load_sender_key_callback),
store_sender_key: C.SignalFfiBridgeSenderKeyStoreStoreSenderKey(C.signal_store_sender_key_callback), store_sender_key: C.SignalFfiSenderKeyStoreStoreSenderKey(C.signal_store_sender_key_callback),
destroy: C.SignalFfiBridgeSenderKeyStoreDestroy(C.signal_destroy_sender_key_store_callback), destroy: C.SignalFfiSenderKeyStoreDestroy(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 *libsignalgo.Address) { func initializeSessions(t *testing.T, aliceStore, bobStore *InMemorySignalProtocolStore, bobAddress, aliceAddress *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, aliceStore, aliceStore) err = libsignalgo.ProcessPreKeyBundle(ctx, bobBundle, bobAddress, aliceAddress, aliceStore, aliceStore)
assert.NoError(t, err) assert.NoError(t, err)
record, err := aliceStore.LoadSession(ctx, bobAddress) record, err := aliceStore.LoadSession(ctx, bobAddress)
@ -132,11 +132,11 @@ func TestSessionCipher(t *testing.T) {
aliceStore := NewInMemorySignalProtocolStore() aliceStore := NewInMemorySignalProtocolStore()
bobStore := NewInMemorySignalProtocolStore() bobStore := NewInMemorySignalProtocolStore()
initializeSessions(t, aliceStore, bobStore, bobAddress) initializeSessions(t, aliceStore, bobStore, bobAddress, aliceAddress)
alicePlaintext := []byte{8, 6, 7, 5, 3, 0, 9} alicePlaintext := []byte{8, 6, 7, 5, 3, 0, 9}
aliceCiphertext, err := libsignalgo.Encrypt(ctx, alicePlaintext, bobAddress, aliceStore, aliceStore) aliceCiphertext, err := libsignalgo.Encrypt(ctx, alicePlaintext, bobAddress, aliceAddress, aliceStore, aliceStore)
assert.NoError(t, err) assert.NoError(t, err)
aliceCiphertextMessageType, err := aliceCiphertext.MessageType() aliceCiphertextMessageType, err := aliceCiphertext.MessageType()
assert.NoError(t, err) assert.NoError(t, err)
@ -147,13 +147,13 @@ func TestSessionCipher(t *testing.T) {
bobCiphertext, err := libsignalgo.DeserializePreKeyMessage(aliceCiphertextSerialized) bobCiphertext, err := libsignalgo.DeserializePreKeyMessage(aliceCiphertextSerialized)
assert.NoError(t, err) assert.NoError(t, err)
bobPlaintext, err := libsignalgo.DecryptPreKey(ctx, bobCiphertext, aliceAddress, bobStore, bobStore, bobStore, bobStore, bobStore) bobPlaintext, err := libsignalgo.DecryptPreKey(ctx, bobCiphertext, aliceAddress, bobAddress, bobStore, bobStore, bobStore, bobStore, bobStore)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, alicePlaintext, bobPlaintext) assert.Equal(t, alicePlaintext, bobPlaintext)
bobPlaintext2 := []byte{23} bobPlaintext2 := []byte{23}
bobCiphertext2, err := libsignalgo.Encrypt(ctx, bobPlaintext2, aliceAddress, bobStore, bobStore) bobCiphertext2, err := libsignalgo.Encrypt(ctx, bobPlaintext2, aliceAddress, bobAddress, bobStore, bobStore)
assert.NoError(t, err) assert.NoError(t, err)
bobCiphertext2MessageType, err := bobCiphertext2.MessageType() bobCiphertext2MessageType, err := bobCiphertext2.MessageType()
assert.NoError(t, err) assert.NoError(t, err)
@ -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, aliceStore, aliceStore) alicePlaintext2, err := libsignalgo.Decrypt(ctx, aliceCiphertext2, bobAddress, aliceAddress, aliceStore, aliceStore)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, bobPlaintext2, alicePlaintext2) assert.Equal(t, bobPlaintext2, alicePlaintext2)
} }
@ -183,11 +183,11 @@ func TestSessionCipherWithBadStore(t *testing.T) {
aliceStore := NewInMemorySignalProtocolStore() aliceStore := NewInMemorySignalProtocolStore()
bobStore := &BadInMemorySignalProtocolStore{NewInMemorySignalProtocolStore()} bobStore := &BadInMemorySignalProtocolStore{NewInMemorySignalProtocolStore()}
initializeSessions(t, aliceStore, bobStore.InMemorySignalProtocolStore, bobAddress) initializeSessions(t, aliceStore, bobStore.InMemorySignalProtocolStore, bobAddress, aliceAddress)
alicePlaintext := []byte{8, 6, 7, 5, 3, 0, 9} alicePlaintext := []byte{8, 6, 7, 5, 3, 0, 9}
aliceCiphertext, err := libsignalgo.Encrypt(ctx, alicePlaintext, bobAddress, aliceStore, aliceStore) aliceCiphertext, err := libsignalgo.Encrypt(ctx, alicePlaintext, bobAddress, aliceAddress, aliceStore, aliceStore)
assert.NoError(t, err) assert.NoError(t, err)
aliceCiphertextMessageType, err := aliceCiphertext.MessageType() aliceCiphertextMessageType, err := aliceCiphertext.MessageType()
assert.NoError(t, err) assert.NoError(t, err)
@ -198,7 +198,7 @@ func TestSessionCipherWithBadStore(t *testing.T) {
bobCiphertext, err := libsignalgo.DeserializePreKeyMessage(aliceCiphertextSerialized) bobCiphertext, err := libsignalgo.DeserializePreKeyMessage(aliceCiphertextSerialized)
assert.NoError(t, err) assert.NoError(t, err)
t.Skip("This test is broken") // TODO fix t.Skip("This test is broken") // TODO fix
_, err = libsignalgo.DecryptPreKey(ctx, bobCiphertext, aliceAddress, bobStore, bobStore, bobStore, bobStore, bobStore) _, err = libsignalgo.DecryptPreKey(ctx, bobCiphertext, aliceAddress, bobAddress, bobStore, bobStore, bobStore, bobStore, bobStore)
require.Error(t, err) require.Error(t, err)
assert.Equal(t, "Test error", err.Error()) assert.Equal(t, "Test error", err.Error())
} }
@ -216,7 +216,7 @@ func TestSealedSenderEncrypt_Repeated(t *testing.T) {
aliceStore := NewInMemorySignalProtocolStore() aliceStore := NewInMemorySignalProtocolStore()
bobStore := NewInMemorySignalProtocolStore() bobStore := NewInMemorySignalProtocolStore()
initializeSessions(t, aliceStore, bobStore, bobAddress) initializeSessions(t, aliceStore, bobStore, bobAddress, aliceAddress)
trustRoot, err := libsignalgo.GenerateIdentityKeyPair() trustRoot, err := libsignalgo.GenerateIdentityKeyPair()
assert.NoError(t, err) assert.NoError(t, err)
@ -241,7 +241,7 @@ func TestSealedSenderEncrypt_Repeated(t *testing.T) {
}() }()
for i := 0; i < 100; i++ { for i := 0; i < 100; i++ {
message := []byte(fmt.Sprintf("%04d vision", i)) message := []byte(fmt.Sprintf("%04d vision", i))
ciphertext, err := libsignalgo.SealedSenderEncryptPlaintext(ctx, message, libsignalgo.UnidentifiedSenderMessageContentHintDefault, bobAddress, senderCert, aliceStore, aliceStore, nil) ciphertext, err := libsignalgo.SealedSenderEncryptPlaintext(ctx, message, libsignalgo.UnidentifiedSenderMessageContentHintDefault, bobAddress, aliceAddress, senderCert, aliceStore, aliceStore, nil)
require.NoError(t, err) require.NoError(t, err)
assert.NotNil(t, ciphertext) assert.NotNil(t, ciphertext)
} }
@ -252,15 +252,18 @@ 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) initializeSessions(t, aliceStore, bobStore, bobAddress, aliceAddress)
session, err := aliceStore.LoadSession(ctx, bobAddress) session, err := aliceStore.LoadSession(ctx, bobAddress)
assert.NoError(t, err) assert.NoError(t, err)
@ -315,7 +318,7 @@ func TestSealedSenderGroupCipher(t *testing.T) {
bobStore := NewInMemorySignalProtocolStore() bobStore := NewInMemorySignalProtocolStore()
initializeSessions(t, aliceStore, bobStore, bobAddress) initializeSessions(t, aliceStore, bobStore, bobAddress, aliceAddress)
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.SignalFfiBridgeSessionStoreLoadSession(C.signal_load_session_callback), load_session: C.SignalFfiSessionStoreLoadSession(C.signal_load_session_callback),
store_session: C.SignalFfiBridgeSessionStoreStoreSession(C.signal_store_session_callback), store_session: C.SignalFfiSessionStoreStoreSession(C.signal_store_session_callback),
destroy: C.SignalFfiBridgeSessionStoreDestroy(C.signal_destroy_session_store_callback), destroy: C.SignalFfiSessionStoreDestroy(C.signal_destroy_session_store_callback),
}} }}
} }

View file

@ -54,6 +54,8 @@ func (FFILogger) Log(level libsignalgo.LogLevel, file string, line uint, message
func (FFILogger) Flush() {} func (FFILogger) Flush() {}
func (FFILogger) Destroy() {}
var loggingSetup = false var loggingSetup = false
func setupLogging() { func setupLogging() {

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.SignalFfiBridgeSignedPreKeyStoreLoadSignedPreKey(C.signal_load_signed_pre_key_callback), load_signed_pre_key: C.SignalFfiSignedPreKeyStoreLoadSignedPreKey(C.signal_load_signed_pre_key_callback),
store_signed_pre_key: C.SignalFfiBridgeSignedPreKeyStoreStoreSignedPreKey(C.signal_store_signed_pre_key_callback), store_signed_pre_key: C.SignalFfiSignedPreKeyStoreStoreSignedPreKey(C.signal_store_signed_pre_key_callback),
destroy: C.SignalFfiBridgeSignedPreKeyStoreDestroy(C.signal_destroy_signed_pre_key_store_callback), destroy: C.SignalFfiSignedPreKeyStoreDestroy(C.signal_destroy_signed_pre_key_store_callback),
}} }}
} }

View file

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

View file

@ -110,6 +110,9 @@ 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 {
@ -121,10 +124,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,20 +468,16 @@ 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
} }

199
pkg/msgconv/imagepack.go Normal file
View file

@ -0,0 +1,199 @@
// 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,6 +34,7 @@ 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 {
@ -44,6 +45,7 @@ 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 {
@ -127,6 +129,30 @@ 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 {
@ -200,6 +226,15 @@ 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,6 +35,7 @@ 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"
@ -136,6 +137,15 @@ 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)
@ -143,12 +153,7 @@ func decryptAttachment(body, key, digest []byte, plaintextDigest bool, size uint
return nil, ErrInvalidDigestForAttachment return nil, ErrInvalidDigestForAttachment
} }
} }
l := len(body) - MACLength decrypted, err := macAndAESDecrypt(body, key)
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
} }
@ -240,6 +245,14 @@ 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
@ -255,11 +268,10 @@ func (cli *Client) UploadAttachment(ctx context.Context, body []byte) (*signalpb
} }
body = extend(body, paddedLen) body = extend(body, paddedLen)
encrypted, err := aesEncrypt(keys[:32], body) encryptedWithMAC, err := macAndAESEncrypt(keys, 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"
@ -467,13 +479,10 @@ 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)
pad := ciphertext[len(ciphertext)-1] return pkcs7.Unpad(ciphertext)
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) {
@ -533,14 +542,11 @@ func aesEncrypt(key, plaintext []byte) ([]byte, error) {
return nil, err return nil, err
} }
pad := aes.BlockSize - len(plaintext)%aes.BlockSize plaintext = pkcs7.Pad(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(ciphertext, plaintext) mode.CryptBlocks(plaintext, plaintext)
return append(iv, ciphertext...), nil return append(iv, plaintext...), nil
} }

View file

@ -619,7 +619,7 @@ func (cli *Client) fetchGroupByID(ctx context.Context, gid types.GroupIdentifier
return nil, fmt.Errorf("failed to get group master key: %w", err) return nil, fmt.Errorf("failed to get group master key: %w", err)
} }
if groupMasterKey == "" { if groupMasterKey == "" {
return nil, fmt.Errorf("No group master key found for group identifier %s", gid) return nil, fmt.Errorf("%w for %s", ErrGroupMasterKeyNotFound, gid)
} }
return cli.fetchGroupWithMasterKey(ctx, groupMasterKey) return cli.fetchGroupWithMasterKey(ctx, groupMasterKey)
} }
@ -1513,11 +1513,15 @@ func (cli *Client) patchGroup(ctx context.Context, groupChange *signalpb.GroupCh
return &changeResp, nil return &changeResp, nil
} }
var ErrGroupMasterKeyNotFound = errors.New("group master key not found in store")
func (cli *Client) UpdateGroup(ctx context.Context, groupChange *GroupChange, gid types.GroupIdentifier) (uint32, error) { func (cli *Client) UpdateGroup(ctx context.Context, groupChange *GroupChange, gid types.GroupIdentifier) (uint32, error) {
log := zerolog.Ctx(ctx).With().Str("action", "UpdateGroup").Logger() log := zerolog.Ctx(ctx).With().Str("action", "UpdateGroup").Logger()
groupMasterKey, err := cli.Store.GroupStore.MasterKeyFromGroupIdentifier(ctx, gid) groupMasterKey, err := cli.Store.GroupStore.MasterKeyFromGroupIdentifier(ctx, gid)
if err != nil { if err != nil {
return 0, fmt.Errorf("failed to get master key for group: %w", err) return 0, fmt.Errorf("failed to get master key for group: %w", err)
} else if groupMasterKey == "" {
return 0, ErrGroupMasterKeyNotFound
} }
groupChange.GroupMasterKey = groupMasterKey groupChange.GroupMasterKey = groupMasterKey
masterKeyBytes := masterKeyToBytes(groupMasterKey) masterKeyBytes := masterKeyToBytes(groupMasterKey)
@ -1752,7 +1756,7 @@ func (cli *Client) GetGroupHistoryPage(ctx context.Context, gid types.GroupIdent
return nil, err return nil, err
} }
if groupMasterKey == "" { if groupMasterKey == "" {
return nil, fmt.Errorf("No group master key found for group identifier %s", gid) return nil, ErrGroupMasterKeyNotFound
} }
masterKeyBytes := masterKeyToBytes(groupMasterKey) masterKeyBytes := masterKeyToBytes(groupMasterKey)
groupAuth, err := cli.GetAuthorizationForToday(ctx, masterKeyBytes) groupAuth, err := cli.GetAuthorizationForToday(ctx, masterKeyBytes)

View file

@ -413,6 +413,10 @@ 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 {
@ -518,6 +522,7 @@ 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

@ -69,6 +69,8 @@ func (l FFILogger) Log(level libsignalgo.LogLevel, file string, line uint, messa
func (FFILogger) Flush() {} func (FFILogger) Flush() {}
func (FFILogger) Destroy() {}
// Ensure FFILogger implements the Logger interface // Ensure FFILogger implements the Logger interface
var _ libsignalgo.Logger = FFILogger{} var _ libsignalgo.Logger = FFILogger{}

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 v6.33.5 // protoc v7.34.1
// 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 v6.33.5 // protoc v7.34.1
// 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 v6.33.5 // protoc v7.34.1
// source: Groups.proto // source: Groups.proto
package signalpb package signalpb
@ -498,6 +498,7 @@ type AccessControl struct {
Attributes AccessControl_AccessRequired `protobuf:"varint,1,opt,name=attributes,proto3,enum=signal.AccessControl_AccessRequired" json:"attributes,omitempty"` Attributes AccessControl_AccessRequired `protobuf:"varint,1,opt,name=attributes,proto3,enum=signal.AccessControl_AccessRequired" json:"attributes,omitempty"`
Members AccessControl_AccessRequired `protobuf:"varint,2,opt,name=members,proto3,enum=signal.AccessControl_AccessRequired" json:"members,omitempty"` Members AccessControl_AccessRequired `protobuf:"varint,2,opt,name=members,proto3,enum=signal.AccessControl_AccessRequired" json:"members,omitempty"`
AddFromInviteLink AccessControl_AccessRequired `protobuf:"varint,3,opt,name=addFromInviteLink,proto3,enum=signal.AccessControl_AccessRequired" json:"addFromInviteLink,omitempty"` AddFromInviteLink AccessControl_AccessRequired `protobuf:"varint,3,opt,name=addFromInviteLink,proto3,enum=signal.AccessControl_AccessRequired" json:"addFromInviteLink,omitempty"`
MemberLabel AccessControl_AccessRequired `protobuf:"varint,4,opt,name=memberLabel,proto3,enum=signal.AccessControl_AccessRequired" json:"memberLabel,omitempty"`
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
} }
@ -553,6 +554,13 @@ func (x *AccessControl) GetAddFromInviteLink() AccessControl_AccessRequired {
return AccessControl_UNKNOWN return AccessControl_UNKNOWN
} }
func (x *AccessControl) GetMemberLabel() AccessControl_AccessRequired {
if x != nil {
return x.MemberLabel
}
return AccessControl_UNKNOWN
}
type Group struct { type Group struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
PublicKey []byte `protobuf:"bytes,1,opt,name=publicKey,proto3" json:"publicKey,omitempty"` PublicKey []byte `protobuf:"bytes,1,opt,name=publicKey,proto3" json:"publicKey,omitempty"`
@ -569,7 +577,8 @@ type Group struct {
MembersPendingAdminApproval []*MemberPendingAdminApproval `protobuf:"bytes,9,rep,name=membersPendingAdminApproval,proto3" json:"membersPendingAdminApproval,omitempty"` MembersPendingAdminApproval []*MemberPendingAdminApproval `protobuf:"bytes,9,rep,name=membersPendingAdminApproval,proto3" json:"membersPendingAdminApproval,omitempty"`
InviteLinkPassword []byte `protobuf:"bytes,10,opt,name=inviteLinkPassword,proto3" json:"inviteLinkPassword,omitempty"` InviteLinkPassword []byte `protobuf:"bytes,10,opt,name=inviteLinkPassword,proto3" json:"inviteLinkPassword,omitempty"`
AnnouncementsOnly bool `protobuf:"varint,12,opt,name=announcements_only,json=announcementsOnly,proto3" json:"announcements_only,omitempty"` AnnouncementsOnly bool `protobuf:"varint,12,opt,name=announcements_only,json=announcementsOnly,proto3" json:"announcements_only,omitempty"`
MembersBanned []*MemberBanned `protobuf:"bytes,13,rep,name=members_banned,json=membersBanned,proto3" json:"members_banned,omitempty"` // next: 14 MembersBanned []*MemberBanned `protobuf:"bytes,13,rep,name=members_banned,json=membersBanned,proto3" json:"members_banned,omitempty"`
Terminated bool `protobuf:"varint,14,opt,name=terminated,proto3" json:"terminated,omitempty"` // next: 15
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
} }
@ -695,6 +704,13 @@ func (x *Group) GetMembersBanned() []*MemberBanned {
return nil return nil
} }
func (x *Group) GetTerminated() bool {
if x != nil {
return x.Terminated
}
return false
}
type GroupAttributeBlob struct { type GroupAttributeBlob struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Content: // Types that are valid to be assigned to Content:
@ -1317,6 +1333,8 @@ type GroupChange_Actions struct {
DeleteMembersBanned []*GroupChange_Actions_DeleteMemberBannedAction `protobuf:"bytes,23,rep,name=delete_members_banned,json=deleteMembersBanned,proto3" json:"delete_members_banned,omitempty"` // change epoch = 4 DeleteMembersBanned []*GroupChange_Actions_DeleteMemberBannedAction `protobuf:"bytes,23,rep,name=delete_members_banned,json=deleteMembersBanned,proto3" json:"delete_members_banned,omitempty"` // change epoch = 4
PromoteMembersPendingPniAciProfileKey []*GroupChange_Actions_PromoteMemberPendingPniAciProfileKeyAction `protobuf:"bytes,24,rep,name=promote_members_pending_pni_aci_profile_key,json=promoteMembersPendingPniAciProfileKey,proto3" json:"promote_members_pending_pni_aci_profile_key,omitempty"` // change epoch = 5 PromoteMembersPendingPniAciProfileKey []*GroupChange_Actions_PromoteMemberPendingPniAciProfileKeyAction `protobuf:"bytes,24,rep,name=promote_members_pending_pni_aci_profile_key,json=promoteMembersPendingPniAciProfileKey,proto3" json:"promote_members_pending_pni_aci_profile_key,omitempty"` // change epoch = 5
ModifyMemberLabels []*GroupChange_Actions_ModifyMemberLabelAction `protobuf:"bytes,26,rep,name=modifyMemberLabels,proto3" json:"modifyMemberLabels,omitempty"` // change epoch = 6; ModifyMemberLabels []*GroupChange_Actions_ModifyMemberLabelAction `protobuf:"bytes,26,rep,name=modifyMemberLabels,proto3" json:"modifyMemberLabels,omitempty"` // change epoch = 6;
ModifyMemberLabelAccess *GroupChange_Actions_ModifyMemberLabelAccessControlAction `protobuf:"bytes,27,opt,name=modifyMemberLabelAccess,proto3" json:"modifyMemberLabelAccess,omitempty"` // change epoch = 6
TerminateGroup *GroupChange_Actions_TerminateGroupAction `protobuf:"bytes,28,opt,name=terminate_group,json=terminateGroup,proto3" json:"terminate_group,omitempty"` // change epoch = 7
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
} }
@ -1533,6 +1551,20 @@ func (x *GroupChange_Actions) GetModifyMemberLabels() []*GroupChange_Actions_Mod
return nil return nil
} }
func (x *GroupChange_Actions) GetModifyMemberLabelAccess() *GroupChange_Actions_ModifyMemberLabelAccessControlAction {
if x != nil {
return x.ModifyMemberLabelAccess
}
return nil
}
func (x *GroupChange_Actions) GetTerminateGroup() *GroupChange_Actions_TerminateGroupAction {
if x != nil {
return x.TerminateGroup
}
return nil
}
type GroupChange_Actions_AddMemberAction struct { type GroupChange_Actions_AddMemberAction struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
Added *Member `protobuf:"bytes,1,opt,name=added,proto3" json:"added,omitempty"` Added *Member `protobuf:"bytes,1,opt,name=added,proto3" json:"added,omitempty"`
@ -2553,6 +2585,50 @@ func (x *GroupChange_Actions_ModifyAddFromInviteLinkAccessControlAction) GetAddF
return AccessControl_UNKNOWN return AccessControl_UNKNOWN
} }
type GroupChange_Actions_ModifyMemberLabelAccessControlAction struct {
state protoimpl.MessageState `protogen:"open.v1"`
MemberLabelAccess AccessControl_AccessRequired `protobuf:"varint,1,opt,name=memberLabelAccess,proto3,enum=signal.AccessControl_AccessRequired" json:"memberLabelAccess,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *GroupChange_Actions_ModifyMemberLabelAccessControlAction) Reset() {
*x = GroupChange_Actions_ModifyMemberLabelAccessControlAction{}
mi := &file_Groups_proto_msgTypes[38]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *GroupChange_Actions_ModifyMemberLabelAccessControlAction) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GroupChange_Actions_ModifyMemberLabelAccessControlAction) ProtoMessage() {}
func (x *GroupChange_Actions_ModifyMemberLabelAccessControlAction) ProtoReflect() protoreflect.Message {
mi := &file_Groups_proto_msgTypes[38]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GroupChange_Actions_ModifyMemberLabelAccessControlAction.ProtoReflect.Descriptor instead.
func (*GroupChange_Actions_ModifyMemberLabelAccessControlAction) Descriptor() ([]byte, []int) {
return file_Groups_proto_rawDescGZIP(), []int{10, 0, 21}
}
func (x *GroupChange_Actions_ModifyMemberLabelAccessControlAction) GetMemberLabelAccess() AccessControl_AccessRequired {
if x != nil {
return x.MemberLabelAccess
}
return AccessControl_UNKNOWN
}
type GroupChange_Actions_ModifyInviteLinkPasswordAction struct { type GroupChange_Actions_ModifyInviteLinkPasswordAction struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
InviteLinkPassword []byte `protobuf:"bytes,1,opt,name=inviteLinkPassword,proto3" json:"inviteLinkPassword,omitempty"` InviteLinkPassword []byte `protobuf:"bytes,1,opt,name=inviteLinkPassword,proto3" json:"inviteLinkPassword,omitempty"`
@ -2562,7 +2638,7 @@ type GroupChange_Actions_ModifyInviteLinkPasswordAction struct {
func (x *GroupChange_Actions_ModifyInviteLinkPasswordAction) Reset() { func (x *GroupChange_Actions_ModifyInviteLinkPasswordAction) Reset() {
*x = GroupChange_Actions_ModifyInviteLinkPasswordAction{} *x = GroupChange_Actions_ModifyInviteLinkPasswordAction{}
mi := &file_Groups_proto_msgTypes[38] mi := &file_Groups_proto_msgTypes[39]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@ -2574,7 +2650,7 @@ func (x *GroupChange_Actions_ModifyInviteLinkPasswordAction) String() string {
func (*GroupChange_Actions_ModifyInviteLinkPasswordAction) ProtoMessage() {} func (*GroupChange_Actions_ModifyInviteLinkPasswordAction) ProtoMessage() {}
func (x *GroupChange_Actions_ModifyInviteLinkPasswordAction) ProtoReflect() protoreflect.Message { func (x *GroupChange_Actions_ModifyInviteLinkPasswordAction) ProtoReflect() protoreflect.Message {
mi := &file_Groups_proto_msgTypes[38] mi := &file_Groups_proto_msgTypes[39]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@ -2587,7 +2663,7 @@ func (x *GroupChange_Actions_ModifyInviteLinkPasswordAction) ProtoReflect() prot
// Deprecated: Use GroupChange_Actions_ModifyInviteLinkPasswordAction.ProtoReflect.Descriptor instead. // Deprecated: Use GroupChange_Actions_ModifyInviteLinkPasswordAction.ProtoReflect.Descriptor instead.
func (*GroupChange_Actions_ModifyInviteLinkPasswordAction) Descriptor() ([]byte, []int) { func (*GroupChange_Actions_ModifyInviteLinkPasswordAction) Descriptor() ([]byte, []int) {
return file_Groups_proto_rawDescGZIP(), []int{10, 0, 21} return file_Groups_proto_rawDescGZIP(), []int{10, 0, 22}
} }
func (x *GroupChange_Actions_ModifyInviteLinkPasswordAction) GetInviteLinkPassword() []byte { func (x *GroupChange_Actions_ModifyInviteLinkPasswordAction) GetInviteLinkPassword() []byte {
@ -2606,7 +2682,7 @@ type GroupChange_Actions_ModifyAnnouncementsOnlyAction struct {
func (x *GroupChange_Actions_ModifyAnnouncementsOnlyAction) Reset() { func (x *GroupChange_Actions_ModifyAnnouncementsOnlyAction) Reset() {
*x = GroupChange_Actions_ModifyAnnouncementsOnlyAction{} *x = GroupChange_Actions_ModifyAnnouncementsOnlyAction{}
mi := &file_Groups_proto_msgTypes[39] mi := &file_Groups_proto_msgTypes[40]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@ -2618,7 +2694,7 @@ func (x *GroupChange_Actions_ModifyAnnouncementsOnlyAction) String() string {
func (*GroupChange_Actions_ModifyAnnouncementsOnlyAction) ProtoMessage() {} func (*GroupChange_Actions_ModifyAnnouncementsOnlyAction) ProtoMessage() {}
func (x *GroupChange_Actions_ModifyAnnouncementsOnlyAction) ProtoReflect() protoreflect.Message { func (x *GroupChange_Actions_ModifyAnnouncementsOnlyAction) ProtoReflect() protoreflect.Message {
mi := &file_Groups_proto_msgTypes[39] mi := &file_Groups_proto_msgTypes[40]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@ -2631,7 +2707,7 @@ func (x *GroupChange_Actions_ModifyAnnouncementsOnlyAction) ProtoReflect() proto
// Deprecated: Use GroupChange_Actions_ModifyAnnouncementsOnlyAction.ProtoReflect.Descriptor instead. // Deprecated: Use GroupChange_Actions_ModifyAnnouncementsOnlyAction.ProtoReflect.Descriptor instead.
func (*GroupChange_Actions_ModifyAnnouncementsOnlyAction) Descriptor() ([]byte, []int) { func (*GroupChange_Actions_ModifyAnnouncementsOnlyAction) Descriptor() ([]byte, []int) {
return file_Groups_proto_rawDescGZIP(), []int{10, 0, 22} return file_Groups_proto_rawDescGZIP(), []int{10, 0, 23}
} }
func (x *GroupChange_Actions_ModifyAnnouncementsOnlyAction) GetAnnouncementsOnly() bool { func (x *GroupChange_Actions_ModifyAnnouncementsOnlyAction) GetAnnouncementsOnly() bool {
@ -2641,6 +2717,42 @@ func (x *GroupChange_Actions_ModifyAnnouncementsOnlyAction) GetAnnouncementsOnly
return false return false
} }
type GroupChange_Actions_TerminateGroupAction struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *GroupChange_Actions_TerminateGroupAction) Reset() {
*x = GroupChange_Actions_TerminateGroupAction{}
mi := &file_Groups_proto_msgTypes[41]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *GroupChange_Actions_TerminateGroupAction) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GroupChange_Actions_TerminateGroupAction) ProtoMessage() {}
func (x *GroupChange_Actions_TerminateGroupAction) ProtoReflect() protoreflect.Message {
mi := &file_Groups_proto_msgTypes[41]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GroupChange_Actions_TerminateGroupAction.ProtoReflect.Descriptor instead.
func (*GroupChange_Actions_TerminateGroupAction) Descriptor() ([]byte, []int) {
return file_Groups_proto_rawDescGZIP(), []int{10, 0, 24}
}
type GroupChanges_GroupChangeState struct { type GroupChanges_GroupChangeState struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
GroupChange *GroupChange `protobuf:"bytes,1,opt,name=groupChange,proto3" json:"groupChange,omitempty"` GroupChange *GroupChange `protobuf:"bytes,1,opt,name=groupChange,proto3" json:"groupChange,omitempty"`
@ -2651,7 +2763,7 @@ type GroupChanges_GroupChangeState struct {
func (x *GroupChanges_GroupChangeState) Reset() { func (x *GroupChanges_GroupChangeState) Reset() {
*x = GroupChanges_GroupChangeState{} *x = GroupChanges_GroupChangeState{}
mi := &file_Groups_proto_msgTypes[40] mi := &file_Groups_proto_msgTypes[42]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@ -2663,7 +2775,7 @@ func (x *GroupChanges_GroupChangeState) String() string {
func (*GroupChanges_GroupChangeState) ProtoMessage() {} func (*GroupChanges_GroupChangeState) ProtoMessage() {}
func (x *GroupChanges_GroupChangeState) ProtoReflect() protoreflect.Message { func (x *GroupChanges_GroupChangeState) ProtoReflect() protoreflect.Message {
mi := &file_Groups_proto_msgTypes[40] mi := &file_Groups_proto_msgTypes[42]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@ -2737,20 +2849,21 @@ const file_Groups_proto_rawDesc = "" +
"\ttimestamp\x18\x04 \x01(\x04R\ttimestamp\"D\n" + "\ttimestamp\x18\x04 \x01(\x04R\ttimestamp\"D\n" +
"\fMemberBanned\x12\x16\n" + "\fMemberBanned\x12\x16\n" +
"\x06userId\x18\x01 \x01(\fR\x06userId\x12\x1c\n" + "\x06userId\x18\x01 \x01(\fR\x06userId\x12\x1c\n" +
"\ttimestamp\x18\x02 \x01(\x04R\ttimestamp\"\xc3\x02\n" + "\ttimestamp\x18\x02 \x01(\x04R\ttimestamp\"\x8b\x03\n" +
"\rAccessControl\x12D\n" + "\rAccessControl\x12D\n" +
"\n" + "\n" +
"attributes\x18\x01 \x01(\x0e2$.signal.AccessControl.AccessRequiredR\n" + "attributes\x18\x01 \x01(\x0e2$.signal.AccessControl.AccessRequiredR\n" +
"attributes\x12>\n" + "attributes\x12>\n" +
"\amembers\x18\x02 \x01(\x0e2$.signal.AccessControl.AccessRequiredR\amembers\x12R\n" + "\amembers\x18\x02 \x01(\x0e2$.signal.AccessControl.AccessRequiredR\amembers\x12R\n" +
"\x11addFromInviteLink\x18\x03 \x01(\x0e2$.signal.AccessControl.AccessRequiredR\x11addFromInviteLink\"X\n" + "\x11addFromInviteLink\x18\x03 \x01(\x0e2$.signal.AccessControl.AccessRequiredR\x11addFromInviteLink\x12F\n" +
"\vmemberLabel\x18\x04 \x01(\x0e2$.signal.AccessControl.AccessRequiredR\vmemberLabel\"X\n" +
"\x0eAccessRequired\x12\v\n" + "\x0eAccessRequired\x12\v\n" +
"\aUNKNOWN\x10\x00\x12\a\n" + "\aUNKNOWN\x10\x00\x12\a\n" +
"\x03ANY\x10\x01\x12\n" + "\x03ANY\x10\x01\x12\n" +
"\n" + "\n" +
"\x06MEMBER\x10\x02\x12\x11\n" + "\x06MEMBER\x10\x02\x12\x11\n" +
"\rADMINISTRATOR\x10\x03\x12\x11\n" + "\rADMINISTRATOR\x10\x03\x12\x11\n" +
"\rUNSATISFIABLE\x10\x04\"\x99\x05\n" + "\rUNSATISFIABLE\x10\x04\"\xb9\x05\n" +
"\x05Group\x12\x1c\n" + "\x05Group\x12\x1c\n" +
"\tpublicKey\x18\x01 \x01(\fR\tpublicKey\x12\x14\n" + "\tpublicKey\x18\x01 \x01(\fR\tpublicKey\x12\x14\n" +
"\x05title\x18\x02 \x01(\fR\x05title\x12 \n" + "\x05title\x18\x02 \x01(\fR\x05title\x12 \n" +
@ -2765,7 +2878,10 @@ const file_Groups_proto_rawDesc = "" +
"\x12inviteLinkPassword\x18\n" + "\x12inviteLinkPassword\x18\n" +
" \x01(\fR\x12inviteLinkPassword\x12-\n" + " \x01(\fR\x12inviteLinkPassword\x12-\n" +
"\x12announcements_only\x18\f \x01(\bR\x11announcementsOnly\x12;\n" + "\x12announcements_only\x18\f \x01(\bR\x11announcementsOnly\x12;\n" +
"\x0emembers_banned\x18\r \x03(\v2\x14.signal.MemberBannedR\rmembersBanned\"\xc3\x01\n" + "\x0emembers_banned\x18\r \x03(\v2\x14.signal.MemberBannedR\rmembersBanned\x12\x1e\n" +
"\n" +
"terminated\x18\x0e \x01(\bR\n" +
"terminated\"\xc3\x01\n" +
"\x12GroupAttributeBlob\x12\x16\n" + "\x12GroupAttributeBlob\x12\x16\n" +
"\x05title\x18\x01 \x01(\tH\x00R\x05title\x12\x18\n" + "\x05title\x18\x01 \x01(\tH\x00R\x05title\x12\x18\n" +
"\x06avatar\x18\x02 \x01(\fH\x00R\x06avatar\x12D\n" + "\x06avatar\x18\x02 \x01(\fH\x00R\x06avatar\x12D\n" +
@ -2789,11 +2905,11 @@ const file_Groups_proto_rawDesc = "" +
"\vmemberCount\x18\x04 \x01(\rR\vmemberCount\x12R\n" + "\vmemberCount\x18\x04 \x01(\rR\vmemberCount\x12R\n" +
"\x11addFromInviteLink\x18\x05 \x01(\x0e2$.signal.AccessControl.AccessRequiredR\x11addFromInviteLink\x12\x18\n" + "\x11addFromInviteLink\x18\x05 \x01(\x0e2$.signal.AccessControl.AccessRequiredR\x11addFromInviteLink\x12\x18\n" +
"\aversion\x18\x06 \x01(\rR\aversion\x122\n" + "\aversion\x18\x06 \x01(\rR\aversion\x122\n" +
"\x14pendingAdminApproval\x18\a \x01(\bR\x14pendingAdminApproval\"\xbb'\n" + "\x14pendingAdminApproval\x18\a \x01(\bR\x14pendingAdminApproval\"\xa6*\n" +
"\vGroupChange\x12\x18\n" + "\vGroupChange\x12\x18\n" +
"\aactions\x18\x01 \x01(\fR\aactions\x12(\n" + "\aactions\x18\x01 \x01(\fR\aactions\x12(\n" +
"\x0fserverSignature\x18\x02 \x01(\fR\x0fserverSignature\x12 \n" + "\x0fserverSignature\x18\x02 \x01(\fR\x0fserverSignature\x12 \n" +
"\vchangeEpoch\x18\x03 \x01(\rR\vchangeEpoch\x1a\xc5&\n" + "\vchangeEpoch\x18\x03 \x01(\rR\vchangeEpoch\x1a\xb0)\n" +
"\aActions\x12\"\n" + "\aActions\x12\"\n" +
"\fsourceUserId\x18\x01 \x01(\fR\fsourceUserId\x12\x19\n" + "\fsourceUserId\x18\x01 \x01(\fR\fsourceUserId\x12\x19\n" +
"\bgroup_id\x18\x19 \x01(\fR\agroupId\x12\x18\n" + "\bgroup_id\x18\x19 \x01(\fR\agroupId\x12\x18\n" +
@ -2823,7 +2939,9 @@ const file_Groups_proto_rawDesc = "" +
"\x12add_members_banned\x18\x16 \x03(\v21.signal.GroupChange.Actions.AddMemberBannedActionR\x10addMembersBanned\x12h\n" + "\x12add_members_banned\x18\x16 \x03(\v21.signal.GroupChange.Actions.AddMemberBannedActionR\x10addMembersBanned\x12h\n" +
"\x15delete_members_banned\x18\x17 \x03(\v24.signal.GroupChange.Actions.DeleteMemberBannedActionR\x13deleteMembersBanned\x12\xa2\x01\n" + "\x15delete_members_banned\x18\x17 \x03(\v24.signal.GroupChange.Actions.DeleteMemberBannedActionR\x13deleteMembersBanned\x12\xa2\x01\n" +
"+promote_members_pending_pni_aci_profile_key\x18\x18 \x03(\v2F.signal.GroupChange.Actions.PromoteMemberPendingPniAciProfileKeyActionR%promoteMembersPendingPniAciProfileKey\x12c\n" + "+promote_members_pending_pni_aci_profile_key\x18\x18 \x03(\v2F.signal.GroupChange.Actions.PromoteMemberPendingPniAciProfileKeyActionR%promoteMembersPendingPniAciProfileKey\x12c\n" +
"\x12modifyMemberLabels\x18\x1a \x03(\v23.signal.GroupChange.Actions.ModifyMemberLabelActionR\x12modifyMemberLabels\x1ag\n" + "\x12modifyMemberLabels\x18\x1a \x03(\v23.signal.GroupChange.Actions.ModifyMemberLabelActionR\x12modifyMemberLabels\x12z\n" +
"\x17modifyMemberLabelAccess\x18\x1b \x01(\v2@.signal.GroupChange.Actions.ModifyMemberLabelAccessControlActionR\x17modifyMemberLabelAccess\x12Y\n" +
"\x0fterminate_group\x18\x1c \x01(\v20.signal.GroupChange.Actions.TerminateGroupActionR\x0eterminateGroup\x1ag\n" +
"\x0fAddMemberAction\x12$\n" + "\x0fAddMemberAction\x12$\n" +
"\x05added\x18\x01 \x01(\v2\x0e.signal.MemberR\x05added\x12.\n" + "\x05added\x18\x01 \x01(\v2\x0e.signal.MemberR\x05added\x12.\n" +
"\x12joinFromInviteLink\x18\x02 \x01(\bR\x12joinFromInviteLink\x1a:\n" + "\x12joinFromInviteLink\x18\x02 \x01(\bR\x12joinFromInviteLink\x1a:\n" +
@ -2882,11 +3000,14 @@ const file_Groups_proto_rawDesc = "" +
" ModifyMembersAccessControlAction\x12J\n" + " ModifyMembersAccessControlAction\x12J\n" +
"\rmembersAccess\x18\x01 \x01(\x0e2$.signal.AccessControl.AccessRequiredR\rmembersAccess\x1a\x8c\x01\n" + "\rmembersAccess\x18\x01 \x01(\x0e2$.signal.AccessControl.AccessRequiredR\rmembersAccess\x1a\x8c\x01\n" +
"*ModifyAddFromInviteLinkAccessControlAction\x12^\n" + "*ModifyAddFromInviteLinkAccessControlAction\x12^\n" +
"\x17addFromInviteLinkAccess\x18\x01 \x01(\x0e2$.signal.AccessControl.AccessRequiredR\x17addFromInviteLinkAccess\x1aP\n" + "\x17addFromInviteLinkAccess\x18\x01 \x01(\x0e2$.signal.AccessControl.AccessRequiredR\x17addFromInviteLinkAccess\x1az\n" +
"$ModifyMemberLabelAccessControlAction\x12R\n" +
"\x11memberLabelAccess\x18\x01 \x01(\x0e2$.signal.AccessControl.AccessRequiredR\x11memberLabelAccess\x1aP\n" +
"\x1eModifyInviteLinkPasswordAction\x12.\n" + "\x1eModifyInviteLinkPasswordAction\x12.\n" +
"\x12inviteLinkPassword\x18\x01 \x01(\fR\x12inviteLinkPassword\x1aN\n" + "\x12inviteLinkPassword\x18\x01 \x01(\fR\x12inviteLinkPassword\x1aN\n" +
"\x1dModifyAnnouncementsOnlyAction\x12-\n" + "\x1dModifyAnnouncementsOnlyAction\x12-\n" +
"\x12announcements_only\x18\x01 \x01(\bR\x11announcementsOnly\"/\n" + "\x12announcements_only\x18\x01 \x01(\bR\x11announcementsOnly\x1a\x16\n" +
"\x14TerminateGroupAction\"/\n" +
"\x17ExternalGroupCredential\x12\x14\n" + "\x17ExternalGroupCredential\x12\x14\n" +
"\x05token\x18\x01 \x01(\tR\x05token\"}\n" + "\x05token\x18\x01 \x01(\tR\x05token\"}\n" +
"\rGroupResponse\x12#\n" + "\rGroupResponse\x12#\n" +
@ -2918,7 +3039,7 @@ func file_Groups_proto_rawDescGZIP() []byte {
} }
var file_Groups_proto_enumTypes = make([]protoimpl.EnumInfo, 2) var file_Groups_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
var file_Groups_proto_msgTypes = make([]protoimpl.MessageInfo, 41) var file_Groups_proto_msgTypes = make([]protoimpl.MessageInfo, 43)
var file_Groups_proto_goTypes = []any{ var file_Groups_proto_goTypes = []any{
(Member_Role)(0), // 0: signal.Member.Role (Member_Role)(0), // 0: signal.Member.Role
(AccessControl_AccessRequired)(0), // 1: signal.AccessControl.AccessRequired (AccessControl_AccessRequired)(0), // 1: signal.AccessControl.AccessRequired
@ -2960,9 +3081,11 @@ var file_Groups_proto_goTypes = []any{
(*GroupChange_Actions_ModifyAttributesAccessControlAction)(nil), // 37: signal.GroupChange.Actions.ModifyAttributesAccessControlAction (*GroupChange_Actions_ModifyAttributesAccessControlAction)(nil), // 37: signal.GroupChange.Actions.ModifyAttributesAccessControlAction
(*GroupChange_Actions_ModifyMembersAccessControlAction)(nil), // 38: signal.GroupChange.Actions.ModifyMembersAccessControlAction (*GroupChange_Actions_ModifyMembersAccessControlAction)(nil), // 38: signal.GroupChange.Actions.ModifyMembersAccessControlAction
(*GroupChange_Actions_ModifyAddFromInviteLinkAccessControlAction)(nil), // 39: signal.GroupChange.Actions.ModifyAddFromInviteLinkAccessControlAction (*GroupChange_Actions_ModifyAddFromInviteLinkAccessControlAction)(nil), // 39: signal.GroupChange.Actions.ModifyAddFromInviteLinkAccessControlAction
(*GroupChange_Actions_ModifyInviteLinkPasswordAction)(nil), // 40: signal.GroupChange.Actions.ModifyInviteLinkPasswordAction (*GroupChange_Actions_ModifyMemberLabelAccessControlAction)(nil), // 40: signal.GroupChange.Actions.ModifyMemberLabelAccessControlAction
(*GroupChange_Actions_ModifyAnnouncementsOnlyAction)(nil), // 41: signal.GroupChange.Actions.ModifyAnnouncementsOnlyAction (*GroupChange_Actions_ModifyInviteLinkPasswordAction)(nil), // 41: signal.GroupChange.Actions.ModifyInviteLinkPasswordAction
(*GroupChanges_GroupChangeState)(nil), // 42: signal.GroupChanges.GroupChangeState (*GroupChange_Actions_ModifyAnnouncementsOnlyAction)(nil), // 42: signal.GroupChange.Actions.ModifyAnnouncementsOnlyAction
(*GroupChange_Actions_TerminateGroupAction)(nil), // 43: signal.GroupChange.Actions.TerminateGroupAction
(*GroupChanges_GroupChangeState)(nil), // 44: signal.GroupChanges.GroupChangeState
} }
var file_Groups_proto_depIdxs = []int32{ var file_Groups_proto_depIdxs = []int32{
0, // 0: signal.Member.role:type_name -> signal.Member.Role 0, // 0: signal.Member.role:type_name -> signal.Member.Role
@ -2970,55 +3093,59 @@ var file_Groups_proto_depIdxs = []int32{
1, // 2: signal.AccessControl.attributes:type_name -> signal.AccessControl.AccessRequired 1, // 2: signal.AccessControl.attributes:type_name -> signal.AccessControl.AccessRequired
1, // 3: signal.AccessControl.members:type_name -> signal.AccessControl.AccessRequired 1, // 3: signal.AccessControl.members:type_name -> signal.AccessControl.AccessRequired
1, // 4: signal.AccessControl.addFromInviteLink:type_name -> signal.AccessControl.AccessRequired 1, // 4: signal.AccessControl.addFromInviteLink:type_name -> signal.AccessControl.AccessRequired
7, // 5: signal.Group.accessControl:type_name -> signal.AccessControl 1, // 5: signal.AccessControl.memberLabel:type_name -> signal.AccessControl.AccessRequired
3, // 6: signal.Group.members:type_name -> signal.Member 7, // 6: signal.Group.accessControl:type_name -> signal.AccessControl
4, // 7: signal.Group.membersPendingProfileKey:type_name -> signal.MemberPendingProfileKey 3, // 7: signal.Group.members:type_name -> signal.Member
5, // 8: signal.Group.membersPendingAdminApproval:type_name -> signal.MemberPendingAdminApproval 4, // 8: signal.Group.membersPendingProfileKey:type_name -> signal.MemberPendingProfileKey
6, // 9: signal.Group.members_banned:type_name -> signal.MemberBanned 5, // 9: signal.Group.membersPendingAdminApproval:type_name -> signal.MemberPendingAdminApproval
17, // 10: signal.GroupInviteLink.contentsV1:type_name -> signal.GroupInviteLink.GroupInviteLinkContentsV1 6, // 10: signal.Group.members_banned:type_name -> signal.MemberBanned
1, // 11: signal.GroupJoinInfo.addFromInviteLink:type_name -> signal.AccessControl.AccessRequired 17, // 11: signal.GroupInviteLink.contentsV1:type_name -> signal.GroupInviteLink.GroupInviteLinkContentsV1
8, // 12: signal.GroupResponse.group:type_name -> signal.Group 1, // 12: signal.GroupJoinInfo.addFromInviteLink:type_name -> signal.AccessControl.AccessRequired
42, // 13: signal.GroupChanges.groupChanges:type_name -> signal.GroupChanges.GroupChangeState 8, // 13: signal.GroupResponse.group:type_name -> signal.Group
12, // 14: signal.GroupChangeResponse.group_change:type_name -> signal.GroupChange 44, // 14: signal.GroupChanges.groupChanges:type_name -> signal.GroupChanges.GroupChangeState
19, // 15: signal.GroupChange.Actions.addMembers:type_name -> signal.GroupChange.Actions.AddMemberAction 12, // 15: signal.GroupChangeResponse.group_change:type_name -> signal.GroupChange
20, // 16: signal.GroupChange.Actions.deleteMembers:type_name -> signal.GroupChange.Actions.DeleteMemberAction 19, // 16: signal.GroupChange.Actions.addMembers:type_name -> signal.GroupChange.Actions.AddMemberAction
21, // 17: signal.GroupChange.Actions.modifyMemberRoles:type_name -> signal.GroupChange.Actions.ModifyMemberRoleAction 20, // 17: signal.GroupChange.Actions.deleteMembers:type_name -> signal.GroupChange.Actions.DeleteMemberAction
23, // 18: signal.GroupChange.Actions.modifyMemberProfileKeys:type_name -> signal.GroupChange.Actions.ModifyMemberProfileKeyAction 21, // 18: signal.GroupChange.Actions.modifyMemberRoles:type_name -> signal.GroupChange.Actions.ModifyMemberRoleAction
24, // 19: signal.GroupChange.Actions.addMembersPendingProfileKey:type_name -> signal.GroupChange.Actions.AddMemberPendingProfileKeyAction 23, // 19: signal.GroupChange.Actions.modifyMemberProfileKeys:type_name -> signal.GroupChange.Actions.ModifyMemberProfileKeyAction
25, // 20: signal.GroupChange.Actions.deleteMembersPendingProfileKey:type_name -> signal.GroupChange.Actions.DeleteMemberPendingProfileKeyAction 24, // 20: signal.GroupChange.Actions.addMembersPendingProfileKey:type_name -> signal.GroupChange.Actions.AddMemberPendingProfileKeyAction
26, // 21: signal.GroupChange.Actions.promoteMembersPendingProfileKey:type_name -> signal.GroupChange.Actions.PromoteMemberPendingProfileKeyAction 25, // 21: signal.GroupChange.Actions.deleteMembersPendingProfileKey:type_name -> signal.GroupChange.Actions.DeleteMemberPendingProfileKeyAction
33, // 22: signal.GroupChange.Actions.modifyTitle:type_name -> signal.GroupChange.Actions.ModifyTitleAction 26, // 22: signal.GroupChange.Actions.promoteMembersPendingProfileKey:type_name -> signal.GroupChange.Actions.PromoteMemberPendingProfileKeyAction
35, // 23: signal.GroupChange.Actions.modifyAvatar:type_name -> signal.GroupChange.Actions.ModifyAvatarAction 33, // 23: signal.GroupChange.Actions.modifyTitle:type_name -> signal.GroupChange.Actions.ModifyTitleAction
36, // 24: signal.GroupChange.Actions.modifyDisappearingMessageTimer:type_name -> signal.GroupChange.Actions.ModifyDisappearingMessageTimerAction 35, // 24: signal.GroupChange.Actions.modifyAvatar:type_name -> signal.GroupChange.Actions.ModifyAvatarAction
37, // 25: signal.GroupChange.Actions.modifyAttributesAccess:type_name -> signal.GroupChange.Actions.ModifyAttributesAccessControlAction 36, // 25: signal.GroupChange.Actions.modifyDisappearingMessageTimer:type_name -> signal.GroupChange.Actions.ModifyDisappearingMessageTimerAction
38, // 26: signal.GroupChange.Actions.modifyMemberAccess:type_name -> signal.GroupChange.Actions.ModifyMembersAccessControlAction 37, // 26: signal.GroupChange.Actions.modifyAttributesAccess:type_name -> signal.GroupChange.Actions.ModifyAttributesAccessControlAction
39, // 27: signal.GroupChange.Actions.modifyAddFromInviteLinkAccess:type_name -> signal.GroupChange.Actions.ModifyAddFromInviteLinkAccessControlAction 38, // 27: signal.GroupChange.Actions.modifyMemberAccess:type_name -> signal.GroupChange.Actions.ModifyMembersAccessControlAction
28, // 28: signal.GroupChange.Actions.addMembersPendingAdminApproval:type_name -> signal.GroupChange.Actions.AddMemberPendingAdminApprovalAction 39, // 28: signal.GroupChange.Actions.modifyAddFromInviteLinkAccess:type_name -> signal.GroupChange.Actions.ModifyAddFromInviteLinkAccessControlAction
29, // 29: signal.GroupChange.Actions.deleteMembersPendingAdminApproval:type_name -> signal.GroupChange.Actions.DeleteMemberPendingAdminApprovalAction 28, // 29: signal.GroupChange.Actions.addMembersPendingAdminApproval:type_name -> signal.GroupChange.Actions.AddMemberPendingAdminApprovalAction
30, // 30: signal.GroupChange.Actions.promoteMembersPendingAdminApproval:type_name -> signal.GroupChange.Actions.PromoteMemberPendingAdminApprovalAction 29, // 30: signal.GroupChange.Actions.deleteMembersPendingAdminApproval:type_name -> signal.GroupChange.Actions.DeleteMemberPendingAdminApprovalAction
40, // 31: signal.GroupChange.Actions.modifyInviteLinkPassword:type_name -> signal.GroupChange.Actions.ModifyInviteLinkPasswordAction 30, // 31: signal.GroupChange.Actions.promoteMembersPendingAdminApproval:type_name -> signal.GroupChange.Actions.PromoteMemberPendingAdminApprovalAction
34, // 32: signal.GroupChange.Actions.modifyDescription:type_name -> signal.GroupChange.Actions.ModifyDescriptionAction 41, // 32: signal.GroupChange.Actions.modifyInviteLinkPassword:type_name -> signal.GroupChange.Actions.ModifyInviteLinkPasswordAction
41, // 33: signal.GroupChange.Actions.modify_announcements_only:type_name -> signal.GroupChange.Actions.ModifyAnnouncementsOnlyAction 34, // 33: signal.GroupChange.Actions.modifyDescription:type_name -> signal.GroupChange.Actions.ModifyDescriptionAction
31, // 34: signal.GroupChange.Actions.add_members_banned:type_name -> signal.GroupChange.Actions.AddMemberBannedAction 42, // 34: signal.GroupChange.Actions.modify_announcements_only:type_name -> signal.GroupChange.Actions.ModifyAnnouncementsOnlyAction
32, // 35: signal.GroupChange.Actions.delete_members_banned:type_name -> signal.GroupChange.Actions.DeleteMemberBannedAction 31, // 35: signal.GroupChange.Actions.add_members_banned:type_name -> signal.GroupChange.Actions.AddMemberBannedAction
27, // 36: signal.GroupChange.Actions.promote_members_pending_pni_aci_profile_key:type_name -> signal.GroupChange.Actions.PromoteMemberPendingPniAciProfileKeyAction 32, // 36: signal.GroupChange.Actions.delete_members_banned:type_name -> signal.GroupChange.Actions.DeleteMemberBannedAction
22, // 37: signal.GroupChange.Actions.modifyMemberLabels:type_name -> signal.GroupChange.Actions.ModifyMemberLabelAction 27, // 37: signal.GroupChange.Actions.promote_members_pending_pni_aci_profile_key:type_name -> signal.GroupChange.Actions.PromoteMemberPendingPniAciProfileKeyAction
3, // 38: signal.GroupChange.Actions.AddMemberAction.added:type_name -> signal.Member 22, // 38: signal.GroupChange.Actions.modifyMemberLabels:type_name -> signal.GroupChange.Actions.ModifyMemberLabelAction
0, // 39: signal.GroupChange.Actions.ModifyMemberRoleAction.role:type_name -> signal.Member.Role 40, // 39: signal.GroupChange.Actions.modifyMemberLabelAccess:type_name -> signal.GroupChange.Actions.ModifyMemberLabelAccessControlAction
4, // 40: signal.GroupChange.Actions.AddMemberPendingProfileKeyAction.added:type_name -> signal.MemberPendingProfileKey 43, // 40: signal.GroupChange.Actions.terminate_group:type_name -> signal.GroupChange.Actions.TerminateGroupAction
5, // 41: signal.GroupChange.Actions.AddMemberPendingAdminApprovalAction.added:type_name -> signal.MemberPendingAdminApproval 3, // 41: signal.GroupChange.Actions.AddMemberAction.added:type_name -> signal.Member
0, // 42: signal.GroupChange.Actions.PromoteMemberPendingAdminApprovalAction.role:type_name -> signal.Member.Role 0, // 42: signal.GroupChange.Actions.ModifyMemberRoleAction.role:type_name -> signal.Member.Role
6, // 43: signal.GroupChange.Actions.AddMemberBannedAction.added:type_name -> signal.MemberBanned 4, // 43: signal.GroupChange.Actions.AddMemberPendingProfileKeyAction.added:type_name -> signal.MemberPendingProfileKey
1, // 44: signal.GroupChange.Actions.ModifyAttributesAccessControlAction.attributesAccess:type_name -> signal.AccessControl.AccessRequired 5, // 44: signal.GroupChange.Actions.AddMemberPendingAdminApprovalAction.added:type_name -> signal.MemberPendingAdminApproval
1, // 45: signal.GroupChange.Actions.ModifyMembersAccessControlAction.membersAccess:type_name -> signal.AccessControl.AccessRequired 0, // 45: signal.GroupChange.Actions.PromoteMemberPendingAdminApprovalAction.role:type_name -> signal.Member.Role
1, // 46: signal.GroupChange.Actions.ModifyAddFromInviteLinkAccessControlAction.addFromInviteLinkAccess:type_name -> signal.AccessControl.AccessRequired 6, // 46: signal.GroupChange.Actions.AddMemberBannedAction.added:type_name -> signal.MemberBanned
12, // 47: signal.GroupChanges.GroupChangeState.groupChange:type_name -> signal.GroupChange 1, // 47: signal.GroupChange.Actions.ModifyAttributesAccessControlAction.attributesAccess:type_name -> signal.AccessControl.AccessRequired
8, // 48: signal.GroupChanges.GroupChangeState.groupState:type_name -> signal.Group 1, // 48: signal.GroupChange.Actions.ModifyMembersAccessControlAction.membersAccess:type_name -> signal.AccessControl.AccessRequired
49, // [49:49] is the sub-list for method output_type 1, // 49: signal.GroupChange.Actions.ModifyAddFromInviteLinkAccessControlAction.addFromInviteLinkAccess:type_name -> signal.AccessControl.AccessRequired
49, // [49:49] is the sub-list for method input_type 1, // 50: signal.GroupChange.Actions.ModifyMemberLabelAccessControlAction.memberLabelAccess:type_name -> signal.AccessControl.AccessRequired
49, // [49:49] is the sub-list for extension type_name 12, // 51: signal.GroupChanges.GroupChangeState.groupChange:type_name -> signal.GroupChange
49, // [49:49] is the sub-list for extension extendee 8, // 52: signal.GroupChanges.GroupChangeState.groupState:type_name -> signal.Group
0, // [0:49] is the sub-list for field type_name 53, // [53:53] is the sub-list for method output_type
53, // [53:53] is the sub-list for method input_type
53, // [53:53] is the sub-list for extension type_name
53, // [53:53] is the sub-list for extension extendee
0, // [0:53] is the sub-list for field type_name
} }
func init() { file_Groups_proto_init() } func init() { file_Groups_proto_init() }
@ -3041,7 +3168,7 @@ func file_Groups_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(), GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_Groups_proto_rawDesc), len(file_Groups_proto_rawDesc)), RawDescriptor: unsafe.Slice(unsafe.StringData(file_Groups_proto_rawDesc), len(file_Groups_proto_rawDesc)),
NumEnums: 2, NumEnums: 2,
NumMessages: 41, NumMessages: 43,
NumExtensions: 0, NumExtensions: 0,
NumServices: 0, NumServices: 0,
}, },

View file

@ -69,6 +69,7 @@ message AccessControl {
AccessRequired attributes = 1; AccessRequired attributes = 1;
AccessRequired members = 2; AccessRequired members = 2;
AccessRequired addFromInviteLink = 3; AccessRequired addFromInviteLink = 3;
AccessRequired memberLabel = 4;
} }
message Group { message Group {
@ -87,7 +88,8 @@ message Group {
bytes inviteLinkPassword = 10; bytes inviteLinkPassword = 10;
bool announcements_only = 12; bool announcements_only = 12;
repeated MemberBanned members_banned = 13; repeated MemberBanned members_banned = 13;
// next: 14 bool terminated = 14;
// next: 15
} }
message GroupAttributeBlob { message GroupAttributeBlob {
@ -225,6 +227,10 @@ message GroupChange {
AccessControl.AccessRequired addFromInviteLinkAccess = 1; AccessControl.AccessRequired addFromInviteLinkAccess = 1;
} }
message ModifyMemberLabelAccessControlAction {
AccessControl.AccessRequired memberLabelAccess = 1;
}
message ModifyInviteLinkPasswordAction { message ModifyInviteLinkPasswordAction {
bytes inviteLinkPassword = 1; bytes inviteLinkPassword = 1;
} }
@ -233,6 +239,8 @@ message GroupChange {
bool announcements_only = 1; bool announcements_only = 1;
} }
message TerminateGroupAction {}
bytes sourceUserId = 1; bytes sourceUserId = 1;
// clients should not provide this value; the server will provide it in the response buffer to ensure the signature is binding to a particular group // clients should not provide this value; the server will provide it in the response buffer to ensure the signature is binding to a particular group
// if clients set it during a request the server will respond with 400. // if clients set it during a request the server will respond with 400.
@ -262,7 +270,9 @@ message GroupChange {
repeated DeleteMemberBannedAction delete_members_banned = 23; // change epoch = 4 repeated DeleteMemberBannedAction delete_members_banned = 23; // change epoch = 4
repeated PromoteMemberPendingPniAciProfileKeyAction promote_members_pending_pni_aci_profile_key = 24; // change epoch = 5 repeated PromoteMemberPendingPniAciProfileKeyAction promote_members_pending_pni_aci_profile_key = 24; // change epoch = 5
repeated ModifyMemberLabelAction modifyMemberLabels = 26; // change epoch = 6; repeated ModifyMemberLabelAction modifyMemberLabels = 26; // change epoch = 6;
// next: 27 ModifyMemberLabelAccessControlAction modifyMemberLabelAccess = 27; // change epoch = 6
TerminateGroupAction terminate_group = 28; // change epoch = 7
// next: 29
} }
bytes actions = 1; bytes actions = 1;

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 v6.33.5 // protoc v7.34.1
// source: Provisioning.proto // source: Provisioning.proto
package signalpb package signalpb
@ -199,7 +199,6 @@ type ProvisionMessage struct {
ProfileKey []byte `protobuf:"bytes,6,opt,name=profileKey" json:"profileKey,omitempty"` ProfileKey []byte `protobuf:"bytes,6,opt,name=profileKey" json:"profileKey,omitempty"`
ReadReceipts *bool `protobuf:"varint,7,opt,name=readReceipts" json:"readReceipts,omitempty"` ReadReceipts *bool `protobuf:"varint,7,opt,name=readReceipts" json:"readReceipts,omitempty"`
ProvisioningVersion *uint32 `protobuf:"varint,9,opt,name=provisioningVersion" json:"provisioningVersion,omitempty"` ProvisioningVersion *uint32 `protobuf:"varint,9,opt,name=provisioningVersion" json:"provisioningVersion,omitempty"`
MasterKey []byte `protobuf:"bytes,13,opt,name=masterKey" json:"masterKey,omitempty"` // Deprecated, but required by linked devices
EphemeralBackupKey []byte `protobuf:"bytes,14,opt,name=ephemeralBackupKey" json:"ephemeralBackupKey,omitempty"` // 32 bytes EphemeralBackupKey []byte `protobuf:"bytes,14,opt,name=ephemeralBackupKey" json:"ephemeralBackupKey,omitempty"` // 32 bytes
AccountEntropyPool *string `protobuf:"bytes,15,opt,name=accountEntropyPool" json:"accountEntropyPool,omitempty"` AccountEntropyPool *string `protobuf:"bytes,15,opt,name=accountEntropyPool" json:"accountEntropyPool,omitempty"`
MediaRootBackupKey []byte `protobuf:"bytes,16,opt,name=mediaRootBackupKey" json:"mediaRootBackupKey,omitempty"` // 32-bytes MediaRootBackupKey []byte `protobuf:"bytes,16,opt,name=mediaRootBackupKey" json:"mediaRootBackupKey,omitempty"` // 32-bytes
@ -323,13 +322,6 @@ func (x *ProvisionMessage) GetProvisioningVersion() uint32 {
return 0 return 0
} }
func (x *ProvisionMessage) GetMasterKey() []byte {
if x != nil {
return x.MasterKey
}
return nil
}
func (x *ProvisionMessage) GetEphemeralBackupKey() []byte { func (x *ProvisionMessage) GetEphemeralBackupKey() []byte {
if x != nil { if x != nil {
return x.EphemeralBackupKey return x.EphemeralBackupKey
@ -374,7 +366,7 @@ const file_Provisioning_proto_rawDesc = "" +
"\aaddress\x18\x01 \x01(\tR\aaddress\"E\n" + "\aaddress\x18\x01 \x01(\tR\aaddress\"E\n" +
"\x11ProvisionEnvelope\x12\x1c\n" + "\x11ProvisionEnvelope\x12\x1c\n" +
"\tpublicKey\x18\x01 \x01(\fR\tpublicKey\x12\x12\n" + "\tpublicKey\x18\x01 \x01(\fR\tpublicKey\x12\x12\n" +
"\x04body\x18\x02 \x01(\fR\x04body\"\xcc\x05\n" + "\x04body\x18\x02 \x01(\fR\x04body\"\xb4\x05\n" +
"\x10ProvisionMessage\x122\n" + "\x10ProvisionMessage\x122\n" +
"\x14aciIdentityKeyPublic\x18\x01 \x01(\fR\x14aciIdentityKeyPublic\x124\n" + "\x14aciIdentityKeyPublic\x18\x01 \x01(\fR\x14aciIdentityKeyPublic\x124\n" +
"\x15aciIdentityKeyPrivate\x18\x02 \x01(\fR\x15aciIdentityKeyPrivate\x122\n" + "\x15aciIdentityKeyPrivate\x18\x02 \x01(\fR\x15aciIdentityKeyPrivate\x122\n" +
@ -390,13 +382,12 @@ const file_Provisioning_proto_rawDesc = "" +
"profileKey\x18\x06 \x01(\fR\n" + "profileKey\x18\x06 \x01(\fR\n" +
"profileKey\x12\"\n" + "profileKey\x12\"\n" +
"\freadReceipts\x18\a \x01(\bR\freadReceipts\x120\n" + "\freadReceipts\x18\a \x01(\bR\freadReceipts\x120\n" +
"\x13provisioningVersion\x18\t \x01(\rR\x13provisioningVersion\x12\x1c\n" + "\x13provisioningVersion\x18\t \x01(\rR\x13provisioningVersion\x12.\n" +
"\tmasterKey\x18\r \x01(\fR\tmasterKey\x12.\n" +
"\x12ephemeralBackupKey\x18\x0e \x01(\fR\x12ephemeralBackupKey\x12.\n" + "\x12ephemeralBackupKey\x18\x0e \x01(\fR\x12ephemeralBackupKey\x12.\n" +
"\x12accountEntropyPool\x18\x0f \x01(\tR\x12accountEntropyPool\x12.\n" + "\x12accountEntropyPool\x18\x0f \x01(\tR\x12accountEntropyPool\x12.\n" +
"\x12mediaRootBackupKey\x18\x10 \x01(\fR\x12mediaRootBackupKey\x12\x1c\n" + "\x12mediaRootBackupKey\x18\x10 \x01(\fR\x12mediaRootBackupKey\x12\x1c\n" +
"\taciBinary\x18\x11 \x01(\fR\taciBinary\x12\x1c\n" + "\taciBinary\x18\x11 \x01(\fR\taciBinary\x12\x1c\n" +
"\tpniBinary\x18\x12 \x01(\fR\tpniBinary*G\n" + "\tpniBinary\x18\x12 \x01(\fR\tpniBinaryJ\x04\b\r\x10\x0e*G\n" +
"\x13ProvisioningVersion\x12\v\n" + "\x13ProvisioningVersion\x12\v\n" +
"\aINITIAL\x10\x00\x12\x12\n" + "\aINITIAL\x10\x00\x12\x12\n" +
"\x0eTABLET_SUPPORT\x10\x01\x12\v\n" + "\x0eTABLET_SUPPORT\x10\x01\x12\v\n" +

View file

@ -38,7 +38,7 @@ message ProvisionMessage {
optional bytes profileKey = 6; optional bytes profileKey = 6;
optional bool readReceipts = 7; optional bool readReceipts = 7;
optional uint32 provisioningVersion = 9; optional uint32 provisioningVersion = 9;
optional bytes masterKey = 13; // Deprecated, but required by linked devices reserved /*masterKey*/ 13; // Deprecated in favor of accountEntropyPool
optional bytes ephemeralBackupKey = 14; // 32 bytes optional bytes ephemeralBackupKey = 14; // 32 bytes
optional string accountEntropyPool = 15; optional string accountEntropyPool = 15;
optional bytes mediaRootBackupKey = 16; // 32-bytes optional bytes mediaRootBackupKey = 16; // 32-bytes

File diff suppressed because it is too large Load diff

View file

@ -13,23 +13,79 @@ option java_outer_classname = "SignalServiceProtos";
message Envelope { message Envelope {
enum Type { enum Type {
UNKNOWN = 0; UNKNOWN = 0;
CIPHERTEXT = 1; // content => (version byte | SignalMessage{Content})
/**
* A double-ratchet message represents a "normal," "unsealed-sender" message
* encrypted using the Double Ratchet within an established Signal session.
* Double-ratchet messages include sender information in the plaintext
* portion of the `Envelope`.
*/
DOUBLE_RATCHET = 1; // content => (version byte | SignalMessage{Content})
reserved 2; reserved 2;
reserved "KEY_EXCHANGE"; reserved "KEY_EXCHANGE";
PREKEY_BUNDLE = 3; // content => (version byte | PreKeySignalMessage{Content})
SERVER_DELIVERY_RECEIPT = 5; // legacyMessage => [] AND content => [] /**
UNIDENTIFIED_SENDER = 6; // legacyMessage => [] AND content => ((version byte | UnidentifiedSenderMessage) OR (version byte | Multi-Recipient Sealed Sender Format)) * A prekey message begins a new Signal session. The `content` of a prekey
SENDERKEY_MESSAGE = 7; // legacyMessage => [] AND content => (version byte | SenderKeyMessage) * message is a superset of a double-ratchet message's `content` and
PLAINTEXT_CONTENT = 8; // legacyMessage => [] AND content => (marker byte | Content) * contains the sender's identity public key and information identifying the
* pre-keys used in the message's ciphertext. Like double-ratchet messages,
* prekey messages contain sender information in the plaintext portion of
* the `Envelope`.
*/
PREKEY_MESSAGE = 3; // content => (version byte | PreKeySignalMessage{Content})
/**
* Server delivery receipts are generated by the server when
* "unsealed-sender" messages are delivered to and acknowledged by the
* destination device. Server delivery receipts identify the sender in the
* plaintext portion of the `Envelope` and have no `content`. Note that
* receipts for sealed-sender messages are generated by clients as
* `UNIDENTIFIED_SENDER` messages.
*
* Note that, with server delivery receipts, the "client timestamp" on
* the envelope refers to the timestamp of the original message (i.e. the
* message the server just delivered) and not to the time of delivery. The
* "server timestamp" refers to the time of delivery.
*/
SERVER_DELIVERY_RECEIPT = 5; // content => []
/**
* An unidentified sender message represents a message with no sender
* information in the plaintext portion of the `Envelope`. Unidentified
* sender messages always contain an additional `subtype` in their
* `content`. They may or may not be part of an existing Signal session
* (i.e. an unidentified sender message may have a "prekey message"
* subtype or may indicate an encryption error).
*/
UNIDENTIFIED_SENDER = 6; // content => ((version byte | UnidentifiedSenderMessage) OR (version byte | Multi-Recipient Sealed Sender Format))
reserved 7;
reserved "SENDERKEY_MESSAGE";
/**
* A plaintext message is used solely to convey encryption error receipts
* and never contains encrypted message content. Encryption error receipts
* must be delivered in plaintext because, encryption/decryption of a prior
* message failed and there is no reason to believe that
* encryption/decryption of subsequent messages with the same key material
* would succeed.
*
* Critically, plaintext messages never have "real" message content
* generated by users. Plaintext messages include sender information.
*/
PLAINTEXT_CONTENT = 8; // content => (marker byte | Content)
// next: 9
} }
optional Type type = 1; optional Type type = 1;
reserved 2; // formerly optional string sourceE164 = 2; reserved 2; // formerly optional string sourceE164 = 2;
optional string sourceServiceId = 11; optional string sourceServiceId = 11;
optional uint32 sourceDevice = 7; optional uint32 sourceDeviceId = 7;
optional string destinationServiceId = 13; optional string destinationServiceId = 13;
reserved 3; // formerly optional string relay = 3; reserved 3; // formerly optional string relay = 3;
optional uint64 timestamp = 5; optional uint64 clientTimestamp = 5;
reserved 6; // formerly optional bytes legacyMessage = 6; // Contains an encrypted DataMessage; this field could have been set historically for type 1 or 3 messages; no longer in use reserved 6; // formerly optional bytes legacyMessage = 6; // Contains an encrypted DataMessage; this field could have been set historically for type 1 or 3 messages; no longer in use
optional bytes content = 8; // Contains an encrypted Content optional bytes content = 8; // Contains an encrypted Content
optional string serverGuid = 9; optional string serverGuid = 9;
@ -48,17 +104,20 @@ message Envelope {
} }
message Content { message Content {
optional DataMessage dataMessage = 1; oneof content {
optional SyncMessage syncMessage = 2; DataMessage dataMessage = 1;
optional CallMessage callMessage = 3; SyncMessage syncMessage = 2;
optional NullMessage nullMessage = 4; CallMessage callMessage = 3;
optional ReceiptMessage receiptMessage = 5; NullMessage nullMessage = 4;
optional TypingMessage typingMessage = 6; ReceiptMessage receiptMessage = 5;
TypingMessage typingMessage = 6;
bytes /* DecryptionErrorMessage */ decryptionErrorMessage = 8;
StoryMessage storyMessage = 9;
EditMessage editMessage = 11;
}
optional bytes /* SenderKeyDistributionMessage */ senderKeyDistributionMessage = 7; optional bytes /* SenderKeyDistributionMessage */ senderKeyDistributionMessage = 7;
optional bytes /* DecryptionErrorMessage */ decryptionErrorMessage = 8;
optional StoryMessage storyMessage = 9;
optional PniSignatureMessage pniSignatureMessage = 10; optional PniSignatureMessage pniSignatureMessage = 10;
optional EditMessage editMessage = 11;
} }
message CallMessage { message CallMessage {
@ -331,8 +390,8 @@ message DataMessage {
message PollVote { message PollVote {
optional bytes targetAuthorAciBinary = 1; optional bytes targetAuthorAciBinary = 1;
optional uint64 targetSentTimestamp = 2; optional uint64 targetSentTimestamp = 2;
repeated uint32 optionIndexes = 3; // must be in the range [0, options.length) from the PollCreate repeated uint32 optionIndexes = 3;
optional uint32 voteCount = 4; // increment this by 1 each time you vote on a given poll optional uint32 voteCount = 4;
} }
message PinMessage { message PinMessage {
@ -349,6 +408,11 @@ message DataMessage {
optional uint64 targetSentTimestamp = 2; optional uint64 targetSentTimestamp = 2;
} }
message AdminDelete {
optional bytes targetAuthorAciBinary = 1; // 16-byte UUID
optional uint64 targetSentTimestamp = 2;
}
optional string body = 1; optional string body = 1;
repeated AttachmentPointer attachments = 2; repeated AttachmentPointer attachments = 2;
reserved /*groupV1*/ 3; reserved /*groupV1*/ 3;
@ -376,7 +440,8 @@ message DataMessage {
optional PollVote pollVote = 26; optional PollVote pollVote = 26;
optional PinMessage pinMessage = 27; optional PinMessage pinMessage = 27;
optional UnpinMessage unpinMessage = 28; optional UnpinMessage unpinMessage = 28;
// NEXT ID: 29 optional AdminDelete adminDelete = 29;
// NEXT ID: 30
} }
message NullMessage { message NullMessage {
@ -435,6 +500,12 @@ message TextAttachment {
} }
message Gradient { message Gradient {
// Color ordering:
// 0 degrees: bottom-to-top
// 90 degrees: left-to-right
// 180 degrees: top-to-bottom
// 270 degrees: right-to-left
optional uint32 startColor = 1; // deprecated: this field will be removed in a future release. optional uint32 startColor = 1; // deprecated: this field will be removed in a future release.
optional uint32 endColor = 2; // deprecated: this field will be removed in a future release. optional uint32 endColor = 2; // deprecated: this field will be removed in a future release.
optional uint32 angle = 3; // degrees optional uint32 angle = 3; // degrees
@ -547,7 +618,7 @@ message SyncMessage {
optional bool unidentifiedDeliveryIndicators = 2; optional bool unidentifiedDeliveryIndicators = 2;
optional bool typingIndicators = 3; optional bool typingIndicators = 3;
reserved /* linkPreviews */ 4; reserved /* linkPreviews */ 4;
optional uint32 provisioningVersion = 5; reserved /* provisioningVersion */ 5;
optional bool linkPreviews = 6; optional bool linkPreviews = 6;
} }
@ -582,7 +653,7 @@ message SyncMessage {
message Keys { message Keys {
reserved /* storageService */ 1; reserved /* storageService */ 1;
optional bytes master = 2; // deprecated: this field will be removed in a future release. reserved /* master */ 2;
optional string accountEntropyPool = 3; optional string accountEntropyPool = 3;
optional bytes mediaRootBackupKey = 4; optional bytes mediaRootBackupKey = 4;
} }
@ -682,7 +753,7 @@ message SyncMessage {
optional bytes rootKey = 1; optional bytes rootKey = 1;
optional bytes adminPasskey = 2; optional bytes adminPasskey = 2;
optional Type type = 3; // defaults to UPDATE optional Type type = 3; // defaults to UPDATE
optional bytes epoch = 4; reserved /*epoch*/ 4;
} }
message CallLogEvent { message CallLogEvent {
@ -779,31 +850,40 @@ message SyncMessage {
} }
} }
optional Sent sent = 1; oneof content {
optional Contacts contacts = 2; Sent sent = 1;
Contacts contacts = 2;
Request request = 4;
Blocked blocked = 6;
Verified verified = 7;
Configuration configuration = 9;
ViewOnceOpen viewOnceOpen = 11;
FetchLatest fetchLatest = 12;
Keys keys = 13;
MessageRequestResponse messageRequestResponse = 14;
OutgoingPayment outgoingPayment = 15;
PniChangeNumber pniChangeNumber = 18;
CallEvent callEvent = 19;
CallLinkUpdate callLinkUpdate = 20;
CallLogEvent callLogEvent = 21;
DeleteForMe deleteForMe = 22;
DeviceNameChange deviceNameChange = 23;
AttachmentBackfillRequest attachmentBackfillRequest = 24;
AttachmentBackfillResponse attachmentBackfillResponse = 25;
}
reserved /*groups*/ 3; reserved /*groups*/ 3;
optional Request request = 4;
// Protobufs don't allow `repeated` fields to be inside of `oneof` so while
// the fields below are mutually exclusive with the rest of the values above
// we have to place them outside of `oneof`.
repeated Read read = 5; repeated Read read = 5;
optional Blocked blocked = 6;
optional Verified verified = 7;
optional Configuration configuration = 9;
optional bytes padding = 8;
repeated StickerPackOperation stickerPackOperation = 10; repeated StickerPackOperation stickerPackOperation = 10;
optional ViewOnceOpen viewOnceOpen = 11;
optional FetchLatest fetchLatest = 12;
optional Keys keys = 13;
optional MessageRequestResponse messageRequestResponse = 14;
optional OutgoingPayment outgoingPayment = 15;
repeated Viewed viewed = 16; repeated Viewed viewed = 16;
reserved /*pniIdentity*/ 17; reserved /*pniIdentity*/ 17;
optional PniChangeNumber pniChangeNumber = 18;
optional CallEvent callEvent = 19; optional bytes padding = 8;
optional CallLinkUpdate callLinkUpdate = 20;
optional CallLogEvent callLogEvent = 21;
optional DeleteForMe deleteForMe = 22;
optional DeviceNameChange deviceNameChange = 23;
optional AttachmentBackfillRequest attachmentBackfillRequest = 24;
optional AttachmentBackfillResponse attachmentBackfillResponse = 25;
} }
message AttachmentPointer { message AttachmentPointer {

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 v6.33.5 // protoc v7.34.1
// 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 v6.33.5 // protoc v7.34.1
// source: StorageService.proto // source: StorageService.proto
package signalpb package signalpb
@ -1401,6 +1401,7 @@ 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
} }
@ -1505,6 +1506,13 @@ 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"`
@ -1598,6 +1606,7 @@ type AccountRecord struct {
NotificationProfileManualOverride *AccountRecord_NotificationProfileManualOverride `protobuf:"bytes,44,opt,name=notificationProfileManualOverride,proto3" json:"notificationProfileManualOverride,omitempty"` NotificationProfileManualOverride *AccountRecord_NotificationProfileManualOverride `protobuf:"bytes,44,opt,name=notificationProfileManualOverride,proto3" json:"notificationProfileManualOverride,omitempty"`
NotificationProfileSyncDisabled bool `protobuf:"varint,45,opt,name=notificationProfileSyncDisabled,proto3" json:"notificationProfileSyncDisabled,omitempty"` NotificationProfileSyncDisabled bool `protobuf:"varint,45,opt,name=notificationProfileSyncDisabled,proto3" json:"notificationProfileSyncDisabled,omitempty"`
AutomaticKeyVerificationDisabled bool `protobuf:"varint,46,opt,name=automaticKeyVerificationDisabled,proto3" json:"automaticKeyVerificationDisabled,omitempty"` AutomaticKeyVerificationDisabled bool `protobuf:"varint,46,opt,name=automaticKeyVerificationDisabled,proto3" json:"automaticKeyVerificationDisabled,omitempty"`
HasSeenAdminDeleteEducationDialog bool `protobuf:"varint,47,opt,name=hasSeenAdminDeleteEducationDialog,proto3" json:"hasSeenAdminDeleteEducationDialog,omitempty"`
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
} }
@ -1905,6 +1914,13 @@ func (x *AccountRecord) GetAutomaticKeyVerificationDisabled() bool {
return false return false
} }
func (x *AccountRecord) GetHasSeenAdminDeleteEducationDialog() bool {
if x != nil {
return x.HasSeenAdminDeleteEducationDialog
}
return false
}
type StoryDistributionListRecord struct { type StoryDistributionListRecord struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
Identifier []byte `protobuf:"bytes,1,opt,name=identifier,proto3" json:"identifier,omitempty"` Identifier []byte `protobuf:"bytes,1,opt,name=identifier,proto3" json:"identifier,omitempty"`
@ -2002,7 +2018,6 @@ type CallLinkRecord struct {
RootKey []byte `protobuf:"bytes,1,opt,name=rootKey,proto3" json:"rootKey,omitempty"` RootKey []byte `protobuf:"bytes,1,opt,name=rootKey,proto3" json:"rootKey,omitempty"`
AdminPasskey []byte `protobuf:"bytes,2,opt,name=adminPasskey,proto3" json:"adminPasskey,omitempty"` AdminPasskey []byte `protobuf:"bytes,2,opt,name=adminPasskey,proto3" json:"adminPasskey,omitempty"`
DeletedAtTimestampMs uint64 `protobuf:"varint,3,opt,name=deletedAtTimestampMs,proto3" json:"deletedAtTimestampMs,omitempty"` DeletedAtTimestampMs uint64 `protobuf:"varint,3,opt,name=deletedAtTimestampMs,proto3" json:"deletedAtTimestampMs,omitempty"`
Epoch []byte `protobuf:"bytes,4,opt,name=epoch,proto3,oneof" json:"epoch,omitempty"`
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
} }
@ -2058,13 +2073,6 @@ func (x *CallLinkRecord) GetDeletedAtTimestampMs() uint64 {
return 0 return 0
} }
func (x *CallLinkRecord) GetEpoch() []byte {
if x != nil {
return x.Epoch
}
return nil
}
type Recipient struct { type Recipient struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
// Types that are valid to be assigned to Identifier: // Types that are valid to be assigned to Identifier:
@ -3195,7 +3203,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\"\xa1\x04\n" + "\x13mutedUntilTimestamp\x18\x06 \x01(\x04R\x13mutedUntilTimestamp\"\xcd\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" +
@ -3207,7 +3215,8 @@ 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\"7\n" + "\vavatarColor\x18\v \x01(\x0e2\x1a.signalservice.AvatarColorH\x00R\vavatarColor\x88\x01\x01\x12*\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" +
@ -3216,7 +3225,7 @@ const file_StorageService_proto_rawDesc = "" +
"\">\n" + "\">\n" +
"\bPayments\x12\x18\n" + "\bPayments\x12\x18\n" +
"\aenabled\x18\x01 \x01(\bR\aenabled\x12\x18\n" + "\aenabled\x18\x01 \x01(\bR\aenabled\x12\x18\n" +
"\aentropy\x18\x02 \x01(\fR\aentropy\"\xcb\x1c\n" + "\aentropy\x18\x02 \x01(\fR\aentropy\"\x99\x1d\n" +
"\rAccountRecord\x12\x1e\n" + "\rAccountRecord\x12\x1e\n" +
"\n" + "\n" +
"profileKey\x18\x01 \x01(\fR\n" + "profileKey\x18\x01 \x01(\fR\n" +
@ -3263,7 +3272,8 @@ const file_StorageService_proto_rawDesc = "" +
"\x11backupTierHistory\x18+ \x01(\v2..signalservice.AccountRecord.BackupTierHistoryR\x11backupTierHistory\x12\x8c\x01\n" + "\x11backupTierHistory\x18+ \x01(\v2..signalservice.AccountRecord.BackupTierHistoryR\x11backupTierHistory\x12\x8c\x01\n" +
"!notificationProfileManualOverride\x18, \x01(\v2>.signalservice.AccountRecord.NotificationProfileManualOverrideR!notificationProfileManualOverride\x12H\n" + "!notificationProfileManualOverride\x18, \x01(\v2>.signalservice.AccountRecord.NotificationProfileManualOverrideR!notificationProfileManualOverride\x12H\n" +
"\x1fnotificationProfileSyncDisabled\x18- \x01(\bR\x1fnotificationProfileSyncDisabled\x12J\n" + "\x1fnotificationProfileSyncDisabled\x18- \x01(\bR\x1fnotificationProfileSyncDisabled\x12J\n" +
" automaticKeyVerificationDisabled\x18. \x01(\bR automaticKeyVerificationDisabled\x1a\xb0\x02\n" + " automaticKeyVerificationDisabled\x18. \x01(\bR automaticKeyVerificationDisabled\x12L\n" +
"!hasSeenAdminDeleteEducationDialog\x18/ \x01(\bR!hasSeenAdminDeleteEducationDialog\x1a\xb0\x02\n" +
"\x12PinnedConversation\x12S\n" + "\x12PinnedConversation\x12S\n" +
"\acontact\x18\x01 \x01(\v27.signalservice.AccountRecord.PinnedConversation.ContactH\x00R\acontact\x12&\n" + "\acontact\x18\x01 \x01(\v27.signalservice.AccountRecord.PinnedConversation.ContactH\x00R\acontact\x12&\n" +
"\rlegacyGroupId\x18\x03 \x01(\fH\x00R\rlegacyGroupId\x12(\n" + "\rlegacyGroupId\x18\x03 \x01(\fH\x00R\rlegacyGroupId\x12(\n" +
@ -3329,13 +3339,11 @@ const file_StorageService_proto_rawDesc = "" +
"\x12deletedAtTimestamp\x18\x04 \x01(\x04R\x12deletedAtTimestamp\x12$\n" + "\x12deletedAtTimestamp\x18\x04 \x01(\x04R\x12deletedAtTimestamp\x12$\n" +
"\rallowsReplies\x18\x05 \x01(\bR\rallowsReplies\x12 \n" + "\rallowsReplies\x18\x05 \x01(\bR\rallowsReplies\x12 \n" +
"\visBlockList\x18\x06 \x01(\bR\visBlockList\x12<\n" + "\visBlockList\x18\x06 \x01(\bR\visBlockList\x12<\n" +
"\x19recipientServiceIdsBinary\x18\a \x03(\fR\x19recipientServiceIdsBinary\"\xa7\x01\n" + "\x19recipientServiceIdsBinary\x18\a \x03(\fR\x19recipientServiceIdsBinary\"\x88\x01\n" +
"\x0eCallLinkRecord\x12\x18\n" + "\x0eCallLinkRecord\x12\x18\n" +
"\arootKey\x18\x01 \x01(\fR\arootKey\x12\"\n" + "\arootKey\x18\x01 \x01(\fR\arootKey\x12\"\n" +
"\fadminPasskey\x18\x02 \x01(\fR\fadminPasskey\x122\n" + "\fadminPasskey\x18\x02 \x01(\fR\fadminPasskey\x122\n" +
"\x14deletedAtTimestampMs\x18\x03 \x01(\x04R\x14deletedAtTimestampMs\x12\x19\n" + "\x14deletedAtTimestampMs\x18\x03 \x01(\x04R\x14deletedAtTimestampMsJ\x04\b\x04\x10\x05\"\x90\x02\n" +
"\x05epoch\x18\x04 \x01(\fH\x00R\x05epoch\x88\x01\x01B\b\n" +
"\x06_epoch\"\x90\x02\n" +
"\tRecipient\x12<\n" + "\tRecipient\x12<\n" +
"\acontact\x18\x01 \x01(\v2 .signalservice.Recipient.ContactH\x00R\acontact\x12&\n" + "\acontact\x18\x01 \x01(\v2 .signalservice.Recipient.ContactH\x00R\acontact\x12&\n" +
"\rlegacyGroupId\x18\x02 \x01(\fH\x00R\rlegacyGroupId\x12(\n" + "\rlegacyGroupId\x18\x02 \x01(\fH\x00R\rlegacyGroupId\x12(\n" +
@ -3531,7 +3539,6 @@ func file_StorageService_proto_init() {
file_StorageService_proto_msgTypes[7].OneofWrappers = []any{} file_StorageService_proto_msgTypes[7].OneofWrappers = []any{}
file_StorageService_proto_msgTypes[9].OneofWrappers = []any{} file_StorageService_proto_msgTypes[9].OneofWrappers = []any{}
file_StorageService_proto_msgTypes[11].OneofWrappers = []any{} file_StorageService_proto_msgTypes[11].OneofWrappers = []any{}
file_StorageService_proto_msgTypes[13].OneofWrappers = []any{}
file_StorageService_proto_msgTypes[14].OneofWrappers = []any{ file_StorageService_proto_msgTypes[14].OneofWrappers = []any{
(*Recipient_Contact_)(nil), (*Recipient_Contact_)(nil),
(*Recipient_LegacyGroupId)(nil), (*Recipient_LegacyGroupId)(nil),

View file

@ -172,6 +172,7 @@ 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 {
@ -296,6 +297,7 @@ message AccountRecord {
NotificationProfileManualOverride notificationProfileManualOverride = 44; NotificationProfileManualOverride notificationProfileManualOverride = 44;
bool notificationProfileSyncDisabled = 45; bool notificationProfileSyncDisabled = 45;
bool automaticKeyVerificationDisabled = 46; bool automaticKeyVerificationDisabled = 46;
bool hasSeenAdminDeleteEducationDialog = 47;
} }
message StoryDistributionListRecord { message StoryDistributionListRecord {
@ -312,7 +314,7 @@ message CallLinkRecord {
bytes rootKey = 1; bytes rootKey = 1;
bytes adminPasskey = 2; bytes adminPasskey = 2;
uint64 deletedAtTimestampMs = 3; uint64 deletedAtTimestampMs = 3;
optional bytes epoch = 4; reserved 4; // was epoch field, never used
} }
message Recipient { message Recipient {

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 v6.33.5 // protoc v7.34.1
// 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 v6.33.5 // protoc v7.34.1
// source: WebSocketResources.proto // source: WebSocketResources.proto
package signalpb package signalpb

File diff suppressed because it is too large Load diff

View file

@ -2,7 +2,7 @@ syntax = "proto3";
package signal.backup; package signal.backup;
option java_package = "org.thoughtcrime.securesms.backup.v2.proto"; option java_package = "org.signal.archive.proto";
option swift_prefix = "BackupProto_"; option swift_prefix = "BackupProto_";
message BackupInfo { message BackupInfo {
@ -135,6 +135,7 @@ message AccountData {
CallsUseLessDataSetting callsUseLessDataSetting = 29; // If unset, treat the same as "Unknown" case CallsUseLessDataSetting callsUseLessDataSetting = 29; // If unset, treat the same as "Unknown" case
bool allowSealedSenderFromAnyone = 30; bool allowSealedSenderFromAnyone = 30;
bool allowAutomaticKeyVerification = 31; bool allowAutomaticKeyVerification = 31;
bool hasSeenAdminDeleteEducationDialog = 32;
} }
message SubscriberData { message SubscriberData {
@ -307,6 +308,7 @@ message Group {
bytes inviteLinkPassword = 10; bytes inviteLinkPassword = 10;
bool announcements_only = 12; bool announcements_only = 12;
repeated MemberBanned members_banned = 13; repeated MemberBanned members_banned = 13;
bool terminated = 14;
} }
message GroupAttributeBlob { message GroupAttributeBlob {
@ -331,6 +333,8 @@ message Group {
reserved /*profileKey*/ 3; // This field is ignored in Backups, in favor of Contact frames for members reserved /*profileKey*/ 3; // This field is ignored in Backups, in favor of Contact frames for members
reserved /*presentation*/ 4; // This field is deprecated in the context of static group state reserved /*presentation*/ 4; // This field is deprecated in the context of static group state
uint32 joinedAtVersion = 5; uint32 joinedAtVersion = 5;
string labelEmoji = 6;
string labelString = 7;
} }
message MemberPendingProfileKey { message MemberPendingProfileKey {
@ -363,6 +367,7 @@ message Group {
AccessRequired attributes = 1; AccessRequired attributes = 1;
AccessRequired members = 2; AccessRequired members = 2;
AccessRequired addFromInviteLink = 3; AccessRequired addFromInviteLink = 3;
AccessRequired memberLabel = 4;
} }
} }
@ -405,7 +410,7 @@ message CallLink {
string name = 3; string name = 3;
Restrictions restrictions = 4; Restrictions restrictions = 4;
uint64 expirationMs = 5; uint64 expirationMs = 5;
optional bytes epoch = 6; // May be absent/empty for older links reserved /*epoch*/ 6;
} }
message AdHocCall { message AdHocCall {
@ -498,6 +503,7 @@ message ChatItem {
ViewOnceMessage viewOnceMessage = 18; ViewOnceMessage viewOnceMessage = 18;
DirectStoryReplyMessage directStoryReplyMessage = 19; // group story reply messages are not backed up DirectStoryReplyMessage directStoryReplyMessage = 19; // group story reply messages are not backed up
Poll poll = 20; Poll poll = 20;
AdminDeletedMessage adminDeletedMessage = 22;
} }
PinDetails pinDetails = 21; // only set if message is pinned PinDetails pinDetails = 21; // only set if message is pinned
@ -898,6 +904,10 @@ message Poll {
repeated Reaction reactions = 5; repeated Reaction reactions = 5;
} }
message AdminDeletedMessage {
uint64 adminId = 1; // id of the admin that deleted the message
}
message ChatUpdateMessage { message ChatUpdateMessage {
// If unset, importers should ignore the update message without throwing an error. // If unset, importers should ignore the update message without throwing an error.
oneof update { oneof update {
@ -1068,6 +1078,8 @@ message GroupChangeChatUpdate {
GroupV2MigrationDroppedMembersUpdate groupV2MigrationDroppedMembersUpdate = 32; GroupV2MigrationDroppedMembersUpdate groupV2MigrationDroppedMembersUpdate = 32;
GroupSequenceOfRequestsAndCancelsUpdate groupSequenceOfRequestsAndCancelsUpdate = 33; GroupSequenceOfRequestsAndCancelsUpdate groupSequenceOfRequestsAndCancelsUpdate = 33;
GroupExpirationTimerUpdate groupExpirationTimerUpdate = 34; GroupExpirationTimerUpdate groupExpirationTimerUpdate = 34;
GroupMemberLabelAccessLevelChangeUpdate groupMemberLabelAccessLevelChangeUpdate = 35;
GroupTerminateChangeUpdate groupTerminateChangeUpdate = 36;
} }
} }
@ -1119,6 +1131,15 @@ message GroupAttributesAccessLevelChangeUpdate {
GroupV2AccessLevel accessLevel = 2; GroupV2AccessLevel accessLevel = 2;
} }
message GroupMemberLabelAccessLevelChangeUpdate {
optional bytes updaterAci = 1;
GroupV2AccessLevel accessLevel = 2;
}
message GroupTerminateChangeUpdate {
optional bytes updaterAci = 1;
}
message GroupAnnouncementOnlyChangeUpdate { message GroupAnnouncementOnlyChangeUpdate {
optional bytes updaterAci = 1; optional bytes updaterAci = 1;
bool isAnnouncementOnly = 2; bool isAnnouncementOnly = 2;

View file

@ -1,8 +1,8 @@
#!/bin/bash #!/bin/bash
set -euo pipefail set -euo pipefail
ANDROID_GIT_REVISION=${1:-bc6114f6e0d3a4b1dcdc472331505f2644185264} ANDROID_GIT_REVISION=${1:-439760e7732585bfd078d92d93732c04cc31e29e}
DESKTOP_GIT_REVISION=${1:-a9063ec0c3c1079072c1e30e0749c1ae8be5500a} DESKTOP_GIT_REVISION=${1:-1b2a3e7b283c32c5654a39da12fc04139fd26dbd}
update_proto() { update_proto() {
case "$1" in case "$1" in
@ -11,9 +11,9 @@ update_proto() {
prefix="lib/libsignal-service/src/main/protowire/" prefix="lib/libsignal-service/src/main/protowire/"
GIT_REVISION=$ANDROID_GIT_REVISION GIT_REVISION=$ANDROID_GIT_REVISION
;; ;;
Signal-Android-App) Signal-Android-Archive)
REPO="Signal-Android" REPO="Signal-Android"
prefix="app/src/main/protowire/" prefix="lib/archive/src/main/protowire/"
GIT_REVISION=$ANDROID_GIT_REVISION GIT_REVISION=$ANDROID_GIT_REVISION
;; ;;
Signal-Desktop) Signal-Desktop)
@ -34,11 +34,10 @@ update_proto Signal-Android StickerResources.proto
update_proto Signal-Android WebSocketResources.proto update_proto Signal-Android WebSocketResources.proto
update_proto Signal-Android StorageService.proto update_proto Signal-Android StorageService.proto
update_proto Signal-Android-App Backup.proto update_proto Signal-Android-Archive Backup.proto
mv Backup.proto backuppb/Backup.proto mv Backup.proto backuppb/Backup.proto
update_proto Signal-Desktop DeviceName.proto update_proto Signal-Desktop DeviceName.proto
# TODO this was moved to libsignal only # TODO these were moved to libsignal only
#update_proto Signal-Desktop UnidentifiedDelivery.proto #update_proto Signal-Desktop UnidentifiedDelivery.proto
# Android has CDSI.proto too, but the types have more generic names (since android uses a different package name) #update_proto Signal-Desktop ContactDiscovery.proto
update_proto Signal-Desktop ContactDiscovery.proto

View file

@ -18,7 +18,6 @@ package signalmeow
import ( import (
"context" "context"
"crypto/hmac"
"encoding/base64" "encoding/base64"
"encoding/json" "encoding/json"
"fmt" "fmt"
@ -166,24 +165,19 @@ func PerformProvisioning(ctx context.Context, deviceStore store.DeviceStore, dev
DeviceID: deviceId, DeviceID: deviceId,
Number: *provisioningMessage.Number, Number: *provisioningMessage.Number,
Password: password, Password: password,
MasterKey: provisioningMessage.GetMasterKey(),
AccountEntropyPool: libsignalgo.AccountEntropyPool(provisioningMessage.GetAccountEntropyPool()), AccountEntropyPool: libsignalgo.AccountEntropyPool(provisioningMessage.GetAccountEntropyPool()),
EphemeralBackupKey: libsignalgo.BytesToBackupKey(provisioningMessage.GetEphemeralBackupKey()), EphemeralBackupKey: libsignalgo.BytesToBackupKey(provisioningMessage.GetEphemeralBackupKey()),
MediaRootBackupKey: libsignalgo.BytesToBackupKey(provisioningMessage.GetMediaRootBackupKey()), MediaRootBackupKey: libsignalgo.BytesToBackupKey(provisioningMessage.GetMediaRootBackupKey()),
} }
if provisioningMessage.GetAccountEntropyPool() != "" { if provisioningMessage.GetAccountEntropyPool() != "" {
var masterKey []byte data.MasterKey, err = libsignalgo.AccountEntropyPool(provisioningMessage.GetAccountEntropyPool()).DeriveSVRKey()
masterKey, err = libsignalgo.AccountEntropyPool(provisioningMessage.GetAccountEntropyPool()).DeriveSVRKey()
if err != nil { if err != nil {
log.Err(err).Msg("Failed to derive master key from account entropy pool") log.Err(err).Msg("Failed to derive master key from account entropy pool")
} else { } else {
log.Debug().Msg("Derived master key from account entropy pool") log.Debug().Msg("Derived master key from account entropy pool")
} }
if data.MasterKey == nil { } else {
data.MasterKey = masterKey log.Warn().Msg("No account entropy pool in provisioning message")
} else if !hmac.Equal(data.MasterKey, masterKey) {
log.Warn().Msg("Master key mismatch")
}
} }
// Store the provisioning data // Store the provisioning data

View file

@ -357,7 +357,7 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb.
return nil, err return nil, err
} }
log = log.With(). log = log.With().
Uint64("envelope_timestamp", envelope.GetTimestamp()). Uint64("envelope_timestamp", envelope.GetClientTimestamp()).
Uint64("server_timestamp", envelope.GetServerTimestamp()). Uint64("server_timestamp", envelope.GetServerTimestamp()).
Logger() Logger()
ctx = log.WithContext(ctx) ctx = log.WithContext(ctx)
@ -368,7 +368,7 @@ func (cli *Client) incomingAPIMessageHandler(ctx context.Context, req *signalpb.
Str("source_service_id", envelope.GetSourceServiceId()). Str("source_service_id", envelope.GetSourceServiceId()).
Hex("destination_service_id_bytes", envelope.GetDestinationServiceIdBinary()). Hex("destination_service_id_bytes", envelope.GetDestinationServiceIdBinary()).
Hex("source_service_id_bytes", envelope.GetSourceServiceIdBinary()). Hex("source_service_id_bytes", envelope.GetSourceServiceIdBinary()).
Uint32("source_device_id", envelope.GetSourceDevice()). Uint32("source_device_id", envelope.GetSourceDeviceId()).
Object("parsed_destination_service_id", destinationServiceID). Object("parsed_destination_service_id", destinationServiceID).
Object("parsed_source_service_id", sourceServiceID). Object("parsed_source_service_id", sourceServiceID).
Int32("envelope_type_id", int32(envelope.GetType())). Int32("envelope_type_id", int32(envelope.GetType())).
@ -436,20 +436,20 @@ func (cli *Client) handleDecryptedResult(
Bool("urgent", envelope.GetUrgent()). Bool("urgent", envelope.GetUrgent()).
Stringer("content_hint", result.ContentHint). Stringer("content_hint", result.ContentHint).
Uint64("server_ts", envelope.GetServerTimestamp()). Uint64("server_ts", envelope.GetServerTimestamp()).
Uint64("client_ts", envelope.GetTimestamp()). Uint64("client_ts", envelope.GetClientTimestamp()).
Msg("No sender address received") Msg("No sender address received")
return nil return nil
} else if theirServiceID, err = result.SenderAddress.NameServiceID(); err != nil { } else if theirServiceID, err = result.SenderAddress.NameServiceID(); err != nil {
log.Warn(). log.Warn().
Uint64("server_ts", envelope.GetServerTimestamp()). Uint64("server_ts", envelope.GetServerTimestamp()).
Uint64("client_ts", envelope.GetTimestamp()). Uint64("client_ts", envelope.GetClientTimestamp()).
Msg("Failed to get sender name as service ID") Msg("Failed to get sender name as service ID")
return fmt.Errorf("failed to get sender name as service ID: %w", err) return fmt.Errorf("failed to get sender name as service ID: %w", err)
} else if theirServiceID.Type != libsignalgo.ServiceIDTypeACI { } else if theirServiceID.Type != libsignalgo.ServiceIDTypeACI {
log.Warn(). log.Warn().
Any("their_service_id", theirServiceID). Any("their_service_id", theirServiceID).
Uint64("server_ts", envelope.GetServerTimestamp()). Uint64("server_ts", envelope.GetServerTimestamp()).
Uint64("client_ts", envelope.GetTimestamp()). Uint64("client_ts", envelope.GetClientTimestamp()).
Msg("Dropping message from non-ACI sender") Msg("Dropping message from non-ACI sender")
return nil return nil
} }
@ -469,7 +469,7 @@ func (cli *Client) handleDecryptedResult(
Bool("urgent", envelope.GetUrgent()). Bool("urgent", envelope.GetUrgent()).
Stringer("content_hint", result.ContentHint). Stringer("content_hint", result.ContentHint).
Uint64("server_ts", envelope.GetServerTimestamp()). Uint64("server_ts", envelope.GetServerTimestamp()).
Uint64("client_ts", envelope.GetTimestamp()). Uint64("client_ts", envelope.GetClientTimestamp()).
Stringer("sender", theirServiceID). Stringer("sender", theirServiceID).
Msg("Ignoring already processed event") Msg("Ignoring already processed event")
return nil return nil
@ -478,7 +478,7 @@ func (cli *Client) handleDecryptedResult(
Bool("urgent", envelope.GetUrgent()). Bool("urgent", envelope.GetUrgent()).
Stringer("content_hint", result.ContentHint). Stringer("content_hint", result.ContentHint).
Uint64("server_ts", envelope.GetServerTimestamp()). Uint64("server_ts", envelope.GetServerTimestamp()).
Uint64("client_ts", envelope.GetTimestamp()). Uint64("client_ts", envelope.GetClientTimestamp()).
Stringer("sender", theirServiceID). Stringer("sender", theirServiceID).
Msg("Decryption error with known sender") Msg("Decryption error with known sender")
// Only send decryption error event if the message was urgent, // Only send decryption error event if the message was urgent,
@ -489,12 +489,12 @@ func (cli *Client) handleDecryptedResult(
handlerSuccess = cli.handleEvent(&events.DecryptionError{ handlerSuccess = cli.handleEvent(&events.DecryptionError{
Sender: theirServiceID.UUID, Sender: theirServiceID.UUID,
Err: result.Err, Err: result.Err,
Timestamp: envelope.GetTimestamp(), Timestamp: envelope.GetClientTimestamp(),
}) })
} }
if result.Retriable { if result.Retriable {
go func() { go func() {
err := cli.sendRetryRequest(ctx, result, envelope.GetTimestamp()) err := cli.sendRetryRequest(ctx, result, envelope.GetClientTimestamp())
if err != nil { if err != nil {
log.Err(err).Msg("Failed to send retry request in background") log.Err(err).Msg("Failed to send retry request in background")
} }
@ -506,15 +506,15 @@ func (cli *Client) handleDecryptedResult(
return nil return nil
} }
content := result.Content rawContent := result.Content
if content == nil { if rawContent == nil {
log.Warn().Msg("Decrypted content is nil") log.Warn().Msg("Decrypted content is nil")
return nil return nil
} }
deviceID, _ := result.SenderAddress.DeviceID() deviceID, _ := result.SenderAddress.DeviceID()
log.Trace(). log.Trace().
Any("raw_data", content). Any("raw_data", rawContent).
Stringer("sender", theirServiceID). Stringer("sender", theirServiceID).
Uint("sender_device", deviceID). Uint("sender_device", deviceID).
Msg("Raw event data") Msg("Raw event data")
@ -531,9 +531,10 @@ func (cli *Client) handleDecryptedResult(
} }
logEvt.Bool("unencrypted", result.Unencrypted).Msg("Decrypted message") logEvt.Bool("unencrypted", result.Unencrypted).Msg("Decrypted message")
if content.DecryptionErrorMessage != nil { // Handle unencrypted types early and refuse any other unencrypted message
if rawContent.GetDecryptionErrorMessage() != nil {
handlerSuccess = true handlerSuccess = true
dem, err := libsignalgo.DeserializeDecryptionErrorMessage(content.DecryptionErrorMessage) dem, err := libsignalgo.DeserializeDecryptionErrorMessage(rawContent.GetDecryptionErrorMessage())
if err != nil { if err != nil {
log.Warn().Err(err).Msg("Failed to unmarshal decryption error message") log.Warn().Err(err).Msg("Failed to unmarshal decryption error message")
} else { } else {
@ -551,9 +552,9 @@ func (cli *Client) handleDecryptedResult(
} }
// If there's a sender key distribution message, process it // If there's a sender key distribution message, process it
if content.GetSenderKeyDistributionMessage() != nil { if rawContent.SenderKeyDistributionMessage != nil {
log.Debug().Msg("content includes sender key distribution message") log.Debug().Msg("content includes sender key distribution message")
skdm, err := libsignalgo.DeserializeSenderKeyDistributionMessage(content.GetSenderKeyDistributionMessage()) skdm, err := libsignalgo.DeserializeSenderKeyDistributionMessage(rawContent.SenderKeyDistributionMessage)
if err != nil { if err != nil {
log.Err(err).Msg("DeserializeSenderKeyDistributionMessage error") log.Err(err).Msg("DeserializeSenderKeyDistributionMessage error")
return err return err
@ -570,6 +571,7 @@ func (cli *Client) handleDecryptedResult(
} }
} }
// If we're getting a message to our PNI, mark it as needing a PNI signature message on the next send
if destinationServiceID == cli.Store.PNIServiceID() { if destinationServiceID == cli.Store.PNIServiceID() {
_, err = cli.Store.RecipientStore.LoadAndUpdateRecipient(ctx, theirServiceID.UUID, uuid.Nil, func(recipient *types.Recipient) (changed bool, err error) { _, err = cli.Store.RecipientStore.LoadAndUpdateRecipient(ctx, theirServiceID.UUID, uuid.Nil, func(recipient *types.Recipient) (changed bool, err error) {
if recipient.Whitelisted == nil { if recipient.Whitelisted == nil {
@ -589,50 +591,57 @@ func (cli *Client) handleDecryptedResult(
} }
} }
if content.PniSignatureMessage != nil { // If we receive a PNI signature message (because we sent to a PNI earlier), process it
if rawContent.PniSignatureMessage != nil {
log.Debug().Msg("Content includes PNI signature message") log.Debug().Msg("Content includes PNI signature message")
err = cli.handlePNISignatureMessage(ctx, theirServiceID, content.PniSignatureMessage) err = cli.handlePNISignatureMessage(ctx, theirServiceID, rawContent.PniSignatureMessage)
if err != nil { if err != nil {
log.Err(err). log.Err(err).
Hex("pni_raw", content.PniSignatureMessage.GetPni()). Hex("pni_raw", rawContent.PniSignatureMessage.GetPni()).
Stringer("aci", theirServiceID.UUID). Stringer("aci", theirServiceID.UUID).
Msg("Failed to verify ACI-PNI mapping") Msg("Failed to verify ACI-PNI mapping")
} }
} }
if content.SyncMessage != nil && theirServiceID == cli.Store.ACIServiceID() {
handlerSuccess = cli.handleSyncMessage(ctx, content.SyncMessage, envelope)
return nil
}
isBlocked, err := cli.Store.RecipientStore.IsBlocked(ctx, theirServiceID.UUID) isBlocked, err := cli.Store.RecipientStore.IsBlocked(ctx, theirServiceID.UUID)
if err != nil { if err != nil {
log.Err(err).Stringer("sender", theirServiceID).Msg("Failed to check if sender is blocked") log.Err(err).Stringer("sender", theirServiceID).Msg("Failed to check if sender is blocked")
} }
var sendDeliveryReceipt bool var sendDeliveryReceipt bool
if content.DataMessage != nil { var deliveryReceiptTS uint64
switch content := rawContent.Content.(type) {
case *signalpb.Content_SyncMessage:
if theirServiceID == cli.Store.ACIServiceID() {
handlerSuccess = cli.handleSyncMessage(ctx, content.SyncMessage, envelope)
}
return nil
case *signalpb.Content_DataMessage:
handlerSuccess, sendDeliveryReceipt = cli.incomingDataMessage( handlerSuccess, sendDeliveryReceipt = cli.incomingDataMessage(
ctx, content.DataMessage, theirServiceID.UUID, theirServiceID, envelope.GetServerTimestamp(), isBlocked, ctx, content.DataMessage, theirServiceID.UUID, theirServiceID, envelope.GetServerTimestamp(), isBlocked,
) )
} else if content.EditMessage != nil { deliveryReceiptTS = content.DataMessage.GetTimestamp()
case *signalpb.Content_EditMessage:
handlerSuccess, sendDeliveryReceipt = cli.incomingEditMessage( handlerSuccess, sendDeliveryReceipt = cli.incomingEditMessage(
ctx, content.EditMessage, theirServiceID.UUID, theirServiceID, envelope.GetServerTimestamp(), isBlocked, ctx, content.EditMessage, theirServiceID.UUID, theirServiceID, envelope.GetServerTimestamp(), isBlocked,
) )
deliveryReceiptTS = content.EditMessage.GetDataMessage().GetTimestamp()
case *signalpb.Content_ReceiptMessage:
if content.ReceiptMessage.GetType() == signalpb.ReceiptMessage_DELIVERY && theirServiceID == cli.Store.ACIServiceID() {
// Ignore delivery receipts from other own devices
return nil
} }
if sendDeliveryReceipt && handlerSuccess { handlerSuccess = cli.handleEvent(&events.Receipt{
err = cli.sendDeliveryReceipts(ctx, []uint64{content.DataMessage.GetTimestamp()}, theirServiceID.UUID) Sender: theirServiceID.UUID,
if err != nil { Content: content.ReceiptMessage,
log.Err(err).Msg("sendDeliveryReceipts error") })
} case *signalpb.Content_TypingMessage:
}
if content.TypingMessage != nil && (!isBlocked || content.TypingMessage.GetGroupId() != nil) {
var groupID types.GroupIdentifier var groupID types.GroupIdentifier
if content.TypingMessage.GetGroupId() != nil { if content.TypingMessage.GetGroupId() != nil {
gidBytes := content.TypingMessage.GetGroupId() gidBytes := content.TypingMessage.GetGroupId()
groupID = types.GroupIdentifier(base64.StdEncoding.EncodeToString(gidBytes)) groupID = types.GroupIdentifier(base64.StdEncoding.EncodeToString(gidBytes))
} }
if !isBlocked || groupID != "" {
// No handler success check here, nobody cares if typing notifications are dropped // No handler success check here, nobody cares if typing notifications are dropped
cli.handleEvent(&events.ChatEvent{ cli.handleEvent(&events.ChatEvent{
Info: events.MessageInfo{ Info: events.MessageInfo{
@ -643,9 +652,8 @@ func (cli *Client) handleDecryptedResult(
Event: content.TypingMessage, Event: content.TypingMessage,
}) })
} }
case *signalpb.Content_CallMessage:
// DM call message (group call is an opaque callMessage and a groupCallUpdate in a dataMessage) if !isBlocked && (content.CallMessage.Offer != nil || content.CallMessage.Hangup != nil) {
if content.CallMessage != nil && (content.CallMessage.Offer != nil || content.CallMessage.Hangup != nil) && !isBlocked {
handlerSuccess = cli.handleEvent(&events.Call{ handlerSuccess = cli.handleEvent(&events.Call{
Info: events.MessageInfo{ Info: events.MessageInfo{
Sender: theirServiceID.UUID, Sender: theirServiceID.UUID,
@ -653,22 +661,30 @@ func (cli *Client) handleDecryptedResult(
ServerTimestamp: envelope.GetServerTimestamp(), ServerTimestamp: envelope.GetServerTimestamp(),
}, },
// CallMessage doesn't have its own timestamp, use one from the envelope // CallMessage doesn't have its own timestamp, use one from the envelope
Timestamp: envelope.GetTimestamp(), Timestamp: envelope.GetClientTimestamp(),
IsRinging: content.CallMessage.Offer != nil, IsRinging: content.CallMessage.Offer != nil,
}) && handlerSuccess })
}
case *signalpb.Content_DecryptionErrorMessage:
// These should've been handled earlier
log.Warn().Msg("Unexpected decryption error message content in decrypted message")
case *signalpb.Content_NullMessage:
// This is intentionally ignored
case *signalpb.Content_StoryMessage:
// This is also ignored for now
default:
if rawContent.PniSignatureMessage == nil && rawContent.SenderKeyDistributionMessage == nil {
log.Warn().Type("content_type", content).Msg("Unrecognized message content type")
}
} }
// Read and delivery receipts if sendDeliveryReceipt && handlerSuccess {
if content.ReceiptMessage != nil { err = cli.sendDeliveryReceipts(ctx, []uint64{deliveryReceiptTS}, theirServiceID.UUID)
if content.GetReceiptMessage().GetType() == signalpb.ReceiptMessage_DELIVERY && theirServiceID == cli.Store.ACIServiceID() { if err != nil {
// Ignore delivery receipts from other own devices log.Err(err).Msg("sendDeliveryReceipts error")
return nil
} }
handlerSuccess = cli.handleEvent(&events.Receipt{
Sender: theirServiceID.UUID,
Content: content.ReceiptMessage,
}) && handlerSuccess
} }
return nil return nil
} }
@ -683,9 +699,9 @@ func (cli *Client) handleSyncMessage(ctx context.Context, msg *signalpb.SyncMess
// TODO: handle more sync messages // TODO: handle more sync messages
handlerSuccess = true handlerSuccess = true
log := zerolog.Ctx(ctx) log := zerolog.Ctx(ctx)
if msg.Keys != nil { switch content := msg.Content.(type) {
aep := libsignalgo.AccountEntropyPool(msg.Keys.GetAccountEntropyPool()) case *signalpb.SyncMessage_Keys_:
cli.Store.MasterKey = msg.Keys.GetMaster() aep := libsignalgo.AccountEntropyPool(content.Keys.GetAccountEntropyPool())
if aep != "" { if aep != "" {
aepMasterKey, err := aep.DeriveSVRKey() aepMasterKey, err := aep.DeriveSVRKey()
if err != nil { if err != nil {
@ -708,11 +724,18 @@ func (cli *Client) handleSyncMessage(ctx context.Context, msg *signalpb.SyncMess
log.Info().Msg("Received master key") log.Info().Msg("Received master key")
go cli.SyncStorage(ctx) go cli.SyncStorage(ctx)
} }
} else if msg.GetFetchLatest().GetType() == signalpb.SyncMessage_FetchLatest_STORAGE_MANIFEST { case *signalpb.SyncMessage_FetchLatest_:
switch content.FetchLatest.GetType() {
case signalpb.SyncMessage_FetchLatest_STORAGE_MANIFEST:
log.Debug().Msg("Received storage manifest fetch latest notice") log.Debug().Msg("Received storage manifest fetch latest notice")
go cli.SyncStorage(ctx) go cli.SyncStorage(ctx)
default:
log.Debug().
Stringer("fetch_latest_type", content.FetchLatest.GetType()).
Msg("Received unknown fetch latest notice")
} }
syncSent := msg.GetSent() case *signalpb.SyncMessage_Sent_:
syncSent := content.Sent
if syncSent.GetMessage() != nil || syncSent.GetEditMessage() != nil { if syncSent.GetMessage() != nil || syncSent.GetEditMessage() != nil {
syncDestinationServiceID, err := ParseStringOrBinaryServiceID(syncSent.GetDestinationServiceId(), syncSent.GetDestinationServiceIdBinary()) syncDestinationServiceID, err := ParseStringOrBinaryServiceID(syncSent.GetDestinationServiceId(), syncSent.GetDestinationServiceIdBinary())
if err != nil && !errors.Is(err, ErrEmptyUUIDInput) { if err != nil && !errors.Is(err, ErrEmptyUUIDInput) {
@ -748,19 +771,18 @@ func (cli *Client) handleSyncMessage(ctx context.Context, msg *signalpb.SyncMess
if syncDestinationServiceID.IsEmpty() && syncSent.GetMessage().GetGroupV2() == nil && syncSent.GetEditMessage().GetDataMessage().GetGroupV2() == nil { if syncDestinationServiceID.IsEmpty() && syncSent.GetMessage().GetGroupV2() == nil && syncSent.GetEditMessage().GetDataMessage().GetGroupV2() == nil {
log.Warn().Msg("sync message sent destination is nil") log.Warn().Msg("sync message sent destination is nil")
} else if msg.Sent.Message != nil { } else if syncSent.Message != nil {
// TODO handle expiration start ts, and maybe the sync message ts? // TODO handle expiration start ts, and maybe the sync message ts?
cli.incomingDataMessage(ctx, msg.Sent.Message, cli.Store.ACI, syncDestinationServiceID, envelope.GetServerTimestamp(), false) cli.incomingDataMessage(ctx, syncSent.Message, cli.Store.ACI, syncDestinationServiceID, envelope.GetServerTimestamp(), false)
} else if msg.Sent.EditMessage != nil { } else if syncSent.EditMessage != nil {
cli.incomingEditMessage(ctx, msg.Sent.EditMessage, cli.Store.ACI, syncDestinationServiceID, envelope.GetServerTimestamp(), false) cli.incomingEditMessage(ctx, syncSent.EditMessage, cli.Store.ACI, syncDestinationServiceID, envelope.GetServerTimestamp(), false)
} }
} }
if msg.Contacts != nil { case *signalpb.SyncMessage_Contacts_:
log.Debug().Msg("Recieved sync message contacts") log.Debug().Msg("Recieved sync message contacts")
blob := msg.Contacts.Blob if content.Contacts.Blob != nil {
if blob != nil {
// TODO roundtrip via disk to save memory // TODO roundtrip via disk to save memory
contactsBytes, err := DownloadAttachmentWithPointer(ctx, blob, nil, nil) contactsBytes, err := DownloadAttachmentWithPointer(ctx, content.Contacts.Blob, nil, nil)
if err != nil { if err != nil {
log.Err(err).Msg("Contacts Sync DownloadAttachment error") log.Err(err).Msg("Contacts Sync DownloadAttachment error")
} }
@ -796,22 +818,14 @@ func (cli *Client) handleSyncMessage(ctx context.Context, msg *signalpb.SyncMess
}) })
} }
} }
} case *signalpb.SyncMessage_DeleteForMe_:
if msg.Read != nil {
handlerSuccess = cli.handleEvent(&events.ReadSelf{
Timestamp: envelope.GetTimestamp(),
Messages: msg.GetRead(),
})
}
if msg.DeleteForMe != nil {
handlerSuccess = cli.handleEvent(&events.DeleteForMe{ handlerSuccess = cli.handleEvent(&events.DeleteForMe{
Timestamp: envelope.GetTimestamp(), Timestamp: envelope.GetClientTimestamp(),
SyncMessage_DeleteForMe: msg.DeleteForMe, SyncMessage_DeleteForMe: content.DeleteForMe,
}) })
} case *signalpb.SyncMessage_MessageRequestResponse_:
if msg.MessageRequestResponse != nil { aciUUID, _ := ParseStringOrBinaryUUID(content.MessageRequestResponse.GetThreadAci(), content.MessageRequestResponse.GetThreadAciBinary())
aciUUID, _ := ParseStringOrBinaryUUID(msg.MessageRequestResponse.GetThreadAci(), msg.MessageRequestResponse.GetThreadAciBinary()) if aciUUID != uuid.Nil && content.MessageRequestResponse.GetType() == signalpb.SyncMessage_MessageRequestResponse_ACCEPT {
if aciUUID != uuid.Nil && msg.MessageRequestResponse.GetType() == signalpb.SyncMessage_MessageRequestResponse_ACCEPT {
_, err := cli.Store.RecipientStore.LoadAndUpdateRecipient(ctx, aciUUID, uuid.Nil, func(recipient *types.Recipient) (changed bool, err error) { _, err := cli.Store.RecipientStore.LoadAndUpdateRecipient(ctx, aciUUID, uuid.Nil, func(recipient *types.Recipient) (changed bool, err error) {
changed = !ptr.Val(recipient.Whitelisted) || recipient.NeedsPNISignature changed = !ptr.Val(recipient.Whitelisted) || recipient.NeedsPNISignature
recipient.Whitelisted = ptr.Ptr(true) recipient.Whitelisted = ptr.Ptr(true)
@ -823,16 +837,23 @@ func (cli *Client) handleSyncMessage(ctx context.Context, msg *signalpb.SyncMess
} }
} }
var groupID *libsignalgo.GroupIdentifier var groupID *libsignalgo.GroupIdentifier
if len(msg.MessageRequestResponse.GroupId) == libsignalgo.GroupIdentifierLength { if len(content.MessageRequestResponse.GroupId) == libsignalgo.GroupIdentifierLength {
groupID = (*libsignalgo.GroupIdentifier)(msg.MessageRequestResponse.GroupId) groupID = (*libsignalgo.GroupIdentifier)(content.MessageRequestResponse.GroupId)
} }
handlerSuccess = cli.handleEvent(&events.MessageRequestResponse{ handlerSuccess = cli.handleEvent(&events.MessageRequestResponse{
Timestamp: envelope.GetTimestamp(), Timestamp: envelope.GetClientTimestamp(),
ThreadACI: aciUUID, ThreadACI: aciUUID,
GroupID: groupID, GroupID: groupID,
Type: msg.MessageRequestResponse.GetType(), Type: content.MessageRequestResponse.GetType(),
Raw: msg.MessageRequestResponse, Raw: content.MessageRequestResponse,
}) })
default:
if msg.Read != nil {
handlerSuccess = cli.handleEvent(&events.ReadSelf{
Timestamp: envelope.GetClientTimestamp(),
Messages: msg.Read,
})
}
} }
return return
} }

View file

@ -64,14 +64,14 @@ func (cli *Client) decryptEnvelope(
} }
return result return result
case signalpb.Envelope_PREKEY_BUNDLE, signalpb.Envelope_CIPHERTEXT: case signalpb.Envelope_PREKEY_MESSAGE, signalpb.Envelope_DOUBLE_RATCHET:
sender, err := sourceServiceID.Address(uint(envelope.GetSourceDevice())) sender, err := sourceServiceID.Address(uint(envelope.GetSourceDeviceId()))
if err != nil { if err != nil {
return DecryptionResult{Err: fmt.Errorf("failed to wrap address: %v", err)} return DecryptionResult{Err: fmt.Errorf("failed to wrap address: %v", err)}
} }
var result *DecryptionResult var result *DecryptionResult
var bundleType string var bundleType string
if *envelope.Type == signalpb.Envelope_PREKEY_BUNDLE { if *envelope.Type == signalpb.Envelope_PREKEY_MESSAGE {
result, err = cli.prekeyDecrypt(ctx, destinationServiceID, sender, envelope.Content, envelope.GetServerTimestamp()) result, err = cli.prekeyDecrypt(ctx, destinationServiceID, sender, envelope.Content, envelope.GetServerTimestamp())
bundleType = "prekey bundle" bundleType = "prekey bundle"
} else { } else {
@ -90,7 +90,7 @@ func (cli *Client) decryptEnvelope(
return *result return *result
case signalpb.Envelope_PLAINTEXT_CONTENT: case signalpb.Envelope_PLAINTEXT_CONTENT:
addr, err := sourceServiceID.Address(uint(envelope.GetSourceDevice())) addr, err := sourceServiceID.Address(uint(envelope.GetSourceDeviceId()))
if err != nil { if err != nil {
return DecryptionResult{Err: fmt.Errorf("failed to wrap address: %v", err)} return DecryptionResult{Err: fmt.Errorf("failed to wrap address: %v", err)}
} }
@ -100,16 +100,13 @@ func (cli *Client) decryptEnvelope(
} }
return DecryptionResult{ return DecryptionResult{
SenderAddress: addr, SenderAddress: addr,
Content: &signalpb.Content{DecryptionErrorMessage: content}, Content: &signalpb.Content{Content: &signalpb.Content_DecryptionErrorMessage{DecryptionErrorMessage: content}},
Unencrypted: true, Unencrypted: true,
} }
case signalpb.Envelope_SERVER_DELIVERY_RECEIPT: case signalpb.Envelope_SERVER_DELIVERY_RECEIPT:
return DecryptionResult{Err: fmt.Errorf("server delivery receipt envelopes are not yet supported")} return DecryptionResult{Err: fmt.Errorf("server delivery receipt envelopes are not yet supported")}
case signalpb.Envelope_SENDERKEY_MESSAGE:
return DecryptionResult{Err: fmt.Errorf("senderkey message envelopes are not yet supported")}
case signalpb.Envelope_UNKNOWN: case signalpb.Envelope_UNKNOWN:
return DecryptionResult{Err: fmt.Errorf("unknown envelope type")} return DecryptionResult{Err: fmt.Errorf("unknown envelope type")}
@ -188,12 +185,17 @@ func (cli *Client) prekeyDecrypt(
if is == nil { if is == nil {
return nil, fmt.Errorf("no identity store found for %s", destination) return nil, fmt.Errorf("no identity store found for %s", destination)
} }
destinationAddress, err := destination.Address(uint(cli.Store.DeviceID))
if err != nil {
return nil, fmt.Errorf("failed to get own/destination address: %w", err)
}
plaintext, ciphertextHash, err := cli.bufferedDecryptTxn(ctx, encryptedContent, serverTimestamp, func(ctx context.Context) ([]byte, error) { plaintext, ciphertextHash, err := cli.bufferedDecryptTxn(ctx, encryptedContent, serverTimestamp, func(ctx context.Context) ([]byte, error) {
return libsignalgo.DecryptPreKey( return libsignalgo.DecryptPreKey(
ctx, ctx,
preKeyMessage, preKeyMessage,
sender, sender,
destinationAddress,
ss, ss,
is, is,
pks, pks,
@ -241,11 +243,16 @@ 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,
) )
@ -394,7 +401,9 @@ func (cli *Client) decryptUnidentifiedSenderEnvelope(ctx context.Context, destin
} }
result.Unencrypted = true result.Unencrypted = true
result.Content = &signalpb.Content{ result.Content = &signalpb.Content{
Content: &signalpb.Content_DecryptionErrorMessage{
DecryptionErrorMessage: usmcContents, DecryptionErrorMessage: usmcContents,
},
} }
return result, err return result, err
default: default:

View file

@ -19,10 +19,12 @@ package signalmeow
import ( import (
"context" "context"
"fmt" "fmt"
"math/rand/v2"
"slices" "slices"
"time" "time"
"github.com/rs/zerolog" "github.com/rs/zerolog"
"go.mau.fi/util/random"
"go.mau.fi/mautrix-signal/pkg/libsignalgo" "go.mau.fi/mautrix-signal/pkg/libsignalgo"
signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf" signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf"
@ -63,7 +65,9 @@ func (cli *Client) sendRetryRequest(ctx context.Context, result DecryptionResult
return fmt.Errorf("failed to create ciphertext message from plaintext content: %w", err) return fmt.Errorf("failed to create ciphertext message from plaintext content: %w", err)
} }
_, err = cli.sendContent(ctx, serviceID, uint64(time.Now().UnixMilli()), &signalpb.Content{ _, err = cli.sendContent(ctx, serviceID, uint64(time.Now().UnixMilli()), &signalpb.Content{
Content: &signalpb.Content_DecryptionErrorMessage{
DecryptionErrorMessage: demBytes, DecryptionErrorMessage: demBytes,
},
}, 0, true, result.GroupID, ctm) }, 0, true, result.GroupID, ctm)
if err != nil { if err != nil {
return fmt.Errorf("failed to send decryption error message: %w", err) return fmt.Errorf("failed to send decryption error message: %w", err)
@ -182,7 +186,11 @@ func (cli *Client) handleRetryRequest(
Msg("Not responding to decryption error message") Msg("Not responding to decryption error message")
return nil return nil
} }
retryContent.NullMessage = &signalpb.NullMessage{} retryContent.Content = &signalpb.Content_NullMessage{
NullMessage: &signalpb.NullMessage{
Padding: random.Bytes(rand.IntN(511) + 1),
},
}
} }
responseTimestamp := uint64(time.Now().UnixMilli()) responseTimestamp := uint64(time.Now().UnixMilli())
if cacheHit { if cacheHit {

View file

@ -22,6 +22,7 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"math/rand/v2"
"net/http" "net/http"
"strconv" "strconv"
"strings" "strings"
@ -31,6 +32,7 @@ import (
"github.com/rs/zerolog" "github.com/rs/zerolog"
"go.mau.fi/util/exfmt" "go.mau.fi/util/exfmt"
"go.mau.fi/util/ptr" "go.mau.fi/util/ptr"
"go.mau.fi/util/random"
"google.golang.org/protobuf/proto" "google.golang.org/protobuf/proto"
"go.mau.fi/mautrix-signal/pkg/libsignalgo" "go.mau.fi/mautrix-signal/pkg/libsignalgo"
@ -171,6 +173,10 @@ func (cli *Client) buildMessagesToSend(
} else if len(sessions) == 0 { } else if len(sessions) == 0 {
return nil, fmt.Errorf("no sessions found for recipient %s", recipient.String()) return nil, fmt.Errorf("no sessions found for recipient %s", recipient.String())
} }
localAddress, err := cli.Store.ACIServiceID().Address(uint(cli.Store.DeviceID))
if err != nil {
return nil, fmt.Errorf("failed to get own address: %w", err)
}
messages := make([]MyMessage, 0, len(sessions)) messages := make([]MyMessage, 0, len(sessions))
for _, tuple := range sessions { for _, tuple := range sessions {
@ -193,7 +199,7 @@ func (cli *Client) buildMessagesToSend(
includeE164 := groupID == nil && cli.Store.AccountRecord.GetPhoneNumberSharingMode() == signalpb.AccountRecord_EVERYBODY includeE164 := groupID == nil && cli.Store.AccountRecord.GetPhoneNumberSharingMode() == signalpb.AccountRecord_EVERYBODY
envelopeType, encryptedPayload, err := cli.buildMessageToSend( envelopeType, encryptedPayload, err := cli.buildMessageToSend(
ctx, tuple.Address, paddedMessage, getContentHint(content), ctmOverride, groupID, includeE164, unauthenticated, ctx, tuple.Address, localAddress, paddedMessage, getContentHint(content), ctmOverride, groupID, includeE164, unauthenticated,
) )
if err != nil { if err != nil {
return nil, err return nil, err
@ -218,11 +224,9 @@ func (cli *Client) buildMessagesToSend(
func ctmTypeToEnvelopeType(ctmType libsignalgo.CiphertextMessageType) signalpb.Envelope_Type { func ctmTypeToEnvelopeType(ctmType libsignalgo.CiphertextMessageType) signalpb.Envelope_Type {
switch ctmType { switch ctmType {
case libsignalgo.CiphertextMessageTypeWhisper: case libsignalgo.CiphertextMessageTypeWhisper:
return signalpb.Envelope_CIPHERTEXT // 2 -> 1 return signalpb.Envelope_DOUBLE_RATCHET // 2 -> 1
case libsignalgo.CiphertextMessageTypePreKey: case libsignalgo.CiphertextMessageTypePreKey:
return signalpb.Envelope_PREKEY_BUNDLE // 3 -> 3 return signalpb.Envelope_PREKEY_MESSAGE // 3 -> 3
case libsignalgo.CiphertextMessageTypeSenderKey:
return signalpb.Envelope_SENDERKEY_MESSAGE // 7 -> 7
case libsignalgo.CiphertextMessageTypePlaintext: case libsignalgo.CiphertextMessageTypePlaintext:
return signalpb.Envelope_PLAINTEXT_CONTENT // 8 -> 8 return signalpb.Envelope_PLAINTEXT_CONTENT // 8 -> 8
default: default:
@ -232,7 +236,7 @@ func ctmTypeToEnvelopeType(ctmType libsignalgo.CiphertextMessageType) signalpb.E
func (cli *Client) buildMessageToSend( func (cli *Client) buildMessageToSend(
ctx context.Context, ctx context.Context,
recipientAddress *libsignalgo.Address, recipientAddress, localAddress *libsignalgo.Address,
paddedMessage []byte, paddedMessage []byte,
contentHint libsignalgo.UnidentifiedSenderMessageContentHint, contentHint libsignalgo.UnidentifiedSenderMessageContentHint,
ciphertextMessage *libsignalgo.CiphertextMessage, ciphertextMessage *libsignalgo.CiphertextMessage,
@ -244,6 +248,7 @@ func (cli *Client) buildMessageToSend(
ctx, ctx,
paddedMessage, paddedMessage,
recipientAddress, recipientAddress,
localAddress,
cli.Store.ACISessionStore, cli.Store.ACISessionStore,
cli.Store.ACIIdentityStore, cli.Store.ACIIdentityStore,
) )
@ -297,11 +302,21 @@ type SendResult interface {
func (gmsr *GroupMessageSendResult) isSendResult() {} func (gmsr *GroupMessageSendResult) isSendResult() {}
func (smsr *SendMessageResult) isSendResult() {} func (smsr *SendMessageResult) isSendResult() {}
func contentFromDataMessage(dataMessage *signalpb.DataMessage) *signalpb.Content { func WrapSyncMessage(content *signalpb.SyncMessage) *signalpb.Content {
content.Padding = random.Bytes(rand.IntN(511) + 1)
return &signalpb.Content{ return &signalpb.Content{
DataMessage: dataMessage, Content: &signalpb.Content_SyncMessage{SyncMessage: content},
} }
} }
func syncSentMessage(sent *signalpb.SyncMessage_Sent) *signalpb.Content {
return WrapSyncMessage(&signalpb.SyncMessage{
Content: &signalpb.SyncMessage_Sent_{
Sent: sent,
},
})
}
func syncMessageFromGroupDataMessage(dataMessage *signalpb.DataMessage, results []SuccessfulSendResult) *signalpb.Content { func syncMessageFromGroupDataMessage(dataMessage *signalpb.DataMessage, results []SuccessfulSendResult) *signalpb.Content {
unidentifiedStatuses := []*signalpb.SyncMessage_Sent_UnidentifiedDeliveryStatus{} unidentifiedStatuses := []*signalpb.SyncMessage_Sent_UnidentifiedDeliveryStatus{}
for _, result := range results { for _, result := range results {
@ -310,17 +325,14 @@ func syncMessageFromGroupDataMessage(dataMessage *signalpb.DataMessage, results
Unidentified: &result.Unidentified, Unidentified: &result.Unidentified,
}) })
} }
return &signalpb.Content{ return syncSentMessage(&signalpb.SyncMessage_Sent{
SyncMessage: &signalpb.SyncMessage{
Sent: &signalpb.SyncMessage_Sent{
Message: dataMessage, Message: dataMessage,
Timestamp: dataMessage.Timestamp, Timestamp: dataMessage.Timestamp,
UnidentifiedStatus: unidentifiedStatuses, UnidentifiedStatus: unidentifiedStatuses,
ExpirationStartTimestamp: ptr.Ptr(uint64(time.Now().UnixMilli())), ExpirationStartTimestamp: ptr.Ptr(uint64(time.Now().UnixMilli())),
}, })
},
}
} }
func syncMessageFromGroupEditMessage(editMessage *signalpb.EditMessage, results []SuccessfulSendResult) *signalpb.Content { func syncMessageFromGroupEditMessage(editMessage *signalpb.EditMessage, results []SuccessfulSendResult) *signalpb.Content {
unidentifiedStatuses := []*signalpb.SyncMessage_Sent_UnidentifiedDeliveryStatus{} unidentifiedStatuses := []*signalpb.SyncMessage_Sent_UnidentifiedDeliveryStatus{}
for _, result := range results { for _, result := range results {
@ -329,22 +341,16 @@ func syncMessageFromGroupEditMessage(editMessage *signalpb.EditMessage, results
Unidentified: &result.Unidentified, Unidentified: &result.Unidentified,
}) })
} }
return &signalpb.Content{ return syncSentMessage(&signalpb.SyncMessage_Sent{
SyncMessage: &signalpb.SyncMessage{
Sent: &signalpb.SyncMessage_Sent{
EditMessage: editMessage, EditMessage: editMessage,
Timestamp: editMessage.GetDataMessage().Timestamp, Timestamp: editMessage.GetDataMessage().Timestamp,
UnidentifiedStatus: unidentifiedStatuses, UnidentifiedStatus: unidentifiedStatuses,
ExpirationStartTimestamp: ptr.Ptr(uint64(time.Now().UnixMilli())), ExpirationStartTimestamp: ptr.Ptr(uint64(time.Now().UnixMilli())),
}, })
},
}
} }
func syncMessageFromSoloDataMessage(dataMessage *signalpb.DataMessage, result SuccessfulSendResult) *signalpb.Content { func syncMessageFromSoloDataMessage(dataMessage *signalpb.DataMessage, result SuccessfulSendResult) *signalpb.Content {
return &signalpb.Content{ return syncSentMessage(&signalpb.SyncMessage_Sent{
SyncMessage: &signalpb.SyncMessage{
Sent: &signalpb.SyncMessage_Sent{
Message: dataMessage, Message: dataMessage,
DestinationE164: result.RecipientE164, DestinationE164: result.RecipientE164,
DestinationServiceIdBinary: result.Recipient.Bytes(), DestinationServiceIdBinary: result.Recipient.Bytes(),
@ -357,15 +363,11 @@ func syncMessageFromSoloDataMessage(dataMessage *signalpb.DataMessage, result Su
DestinationPniIdentityKey: result.DestinationPNIIdentityKey.TrySerialize(), DestinationPniIdentityKey: result.DestinationPNIIdentityKey.TrySerialize(),
}, },
}, },
}, })
},
}
} }
func syncMessageFromSoloEditMessage(editMessage *signalpb.EditMessage, result SuccessfulSendResult) *signalpb.Content { func syncMessageFromSoloEditMessage(editMessage *signalpb.EditMessage, result SuccessfulSendResult) *signalpb.Content {
return &signalpb.Content{ return syncSentMessage(&signalpb.SyncMessage_Sent{
SyncMessage: &signalpb.SyncMessage{
Sent: &signalpb.SyncMessage_Sent{
EditMessage: editMessage, EditMessage: editMessage,
DestinationE164: result.RecipientE164, DestinationE164: result.RecipientE164,
DestinationServiceIdBinary: result.Recipient.Bytes(), DestinationServiceIdBinary: result.Recipient.Bytes(),
@ -378,21 +380,11 @@ func syncMessageFromSoloEditMessage(editMessage *signalpb.EditMessage, result Su
DestinationPniIdentityKey: result.DestinationPNIIdentityKey.TrySerialize(), DestinationPniIdentityKey: result.DestinationPNIIdentityKey.TrySerialize(),
}, },
}, },
}, })
},
}
} }
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 { if *receiptMessage.Type != signalpb.ReceiptMessage_READ || messageSender.Type != libsignalgo.ServiceIDTypeACI {
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{}
@ -402,11 +394,9 @@ func syncMessageFromReadReceiptMessage(ctx context.Context, receiptMessage *sign
SenderAci: proto.String(messageSender.UUID.String()), SenderAci: proto.String(messageSender.UUID.String()),
}) })
} }
return &signalpb.Content{ return WrapSyncMessage(&signalpb.SyncMessage{
SyncMessage: &signalpb.SyncMessage{
Read: read, Read: read,
}, })
}
} }
func (cli *Client) SendContactSyncRequest(ctx context.Context) error { func (cli *Client) SendContactSyncRequest(ctx context.Context) error {
@ -422,13 +412,13 @@ func (cli *Client) SendContactSyncRequest(ctx context.Context) error {
} }
cli.LastContactRequestTime = time.Now() cli.LastContactRequestTime = time.Now()
_, err := cli.sendContent(ctx, cli.Store.ACIServiceID(), uint64(time.Now().UnixMilli()), &signalpb.Content{ _, err := cli.sendContent(ctx, cli.Store.ACIServiceID(), uint64(time.Now().UnixMilli()), WrapSyncMessage(&signalpb.SyncMessage{
SyncMessage: &signalpb.SyncMessage{ Content: &signalpb.SyncMessage_Request_{
Request: &signalpb.SyncMessage_Request{ Request: &signalpb.SyncMessage_Request{
Type: signalpb.SyncMessage_Request_CONTACTS.Enum(), Type: signalpb.SyncMessage_Request_CONTACTS.Enum(),
}, },
}, },
}, 0, false, nil, nil) }), 0, false, nil, nil)
if err != nil { if err != nil {
log.Err(err).Msg("Failed to send contact sync request message to myself") log.Err(err).Msg("Failed to send contact sync request message to myself")
return err return err
@ -442,13 +432,13 @@ func (cli *Client) SendStorageMasterKeyRequest(ctx context.Context) error {
Logger() Logger()
ctx = log.WithContext(ctx) ctx = log.WithContext(ctx)
_, err := cli.sendContent(ctx, cli.Store.ACIServiceID(), uint64(time.Now().UnixMilli()), &signalpb.Content{ _, err := cli.sendContent(ctx, cli.Store.ACIServiceID(), uint64(time.Now().UnixMilli()), WrapSyncMessage(&signalpb.SyncMessage{
SyncMessage: &signalpb.SyncMessage{ Content: &signalpb.SyncMessage_Request_{
Request: &signalpb.SyncMessage_Request{ Request: &signalpb.SyncMessage_Request{
Type: signalpb.SyncMessage_Request_KEYS.Enum(), Type: signalpb.SyncMessage_Request_KEYS.Enum(),
}, },
}, },
}, 0, false, nil, nil) }), 0, false, nil, nil)
if err != nil { if err != nil {
log.Err(err).Msg("Failed to send key sync request message to myself") log.Err(err).Msg("Failed to send key sync request message to myself")
return err return err
@ -468,38 +458,47 @@ func TypingMessage(isTyping bool) *signalpb.Content {
} else { } else {
action = signalpb.TypingMessage_STOPPED action = signalpb.TypingMessage_STOPPED
} }
tm := &signalpb.TypingMessage{ return &signalpb.Content{
Content: &signalpb.Content_TypingMessage{
TypingMessage: &signalpb.TypingMessage{
Timestamp: &timestamp, Timestamp: &timestamp,
Action: &action, Action: &action,
} },
return &signalpb.Content{ },
TypingMessage: tm,
} }
} }
func DeliveredReceiptMessageForTimestamps(timestamps []uint64) *signalpb.Content { func DeliveredReceiptMessageForTimestamps(timestamps []uint64) *signalpb.Content {
rm := &signalpb.ReceiptMessage{ return &signalpb.Content{
Content: &signalpb.Content_ReceiptMessage{
ReceiptMessage: &signalpb.ReceiptMessage{
Timestamp: timestamps, Timestamp: timestamps,
Type: signalpb.ReceiptMessage_DELIVERY.Enum(), Type: signalpb.ReceiptMessage_DELIVERY.Enum(),
} },
return &signalpb.Content{ },
ReceiptMessage: rm,
} }
} }
func ReadReceptMessageForTimestamps(timestamps []uint64) *signalpb.Content { func ReadReceptMessageForTimestamps(timestamps []uint64) *signalpb.Content {
rm := &signalpb.ReceiptMessage{ return &signalpb.Content{
Content: &signalpb.Content_ReceiptMessage{
ReceiptMessage: &signalpb.ReceiptMessage{
Timestamp: timestamps, Timestamp: timestamps,
Type: signalpb.ReceiptMessage_READ.Enum(), Type: signalpb.ReceiptMessage_READ.Enum(),
} },
return &signalpb.Content{ },
ReceiptMessage: rm,
} }
} }
func wrapDataMessageInContent(dm *signalpb.DataMessage) *signalpb.Content { func WrapDataMessage(dm *signalpb.DataMessage) *signalpb.Content {
return &signalpb.Content{ return &signalpb.Content{
DataMessage: dm, Content: &signalpb.Content_DataMessage{DataMessage: dm},
}
}
func WrapEditMessage(dm *signalpb.EditMessage) *signalpb.Content {
return &signalpb.Content{
Content: &signalpb.Content_EditMessage{EditMessage: dm},
} }
} }
@ -526,7 +525,7 @@ func (cli *Client) SendGroupUpdate(ctx context.Context, group *Group, groupConte
Timestamp: &timestamp, Timestamp: &timestamp,
GroupV2: groupContext, GroupV2: groupContext,
} }
content := wrapDataMessageInContent(dm) content := WrapDataMessage(dm)
var recipients []libsignalgo.ServiceID var recipients []libsignalgo.ServiceID
for _, member := range group.Members { for _, member := range group.Members {
serviceID := member.UserServiceID() serviceID := member.UserServiceID()
@ -564,13 +563,14 @@ func (cli *Client) SendGroupMessage(ctx context.Context, gid types.GroupIdentifi
return nil, err return nil, err
} }
var messageTimestamp uint64 var messageTimestamp uint64
if content.GetDataMessage() != nil { switch content := content.Content.(type) {
case *signalpb.Content_DataMessage:
messageTimestamp = content.DataMessage.GetTimestamp() messageTimestamp = content.DataMessage.GetTimestamp()
content.DataMessage.GroupV2 = groupMetadataForDataMessage(*group) content.DataMessage.GroupV2 = groupMetadataForDataMessage(*group)
} else if content.GetEditMessage().GetDataMessage() != nil { case *signalpb.Content_EditMessage:
messageTimestamp = content.EditMessage.DataMessage.GetTimestamp() messageTimestamp = content.EditMessage.DataMessage.GetTimestamp()
content.EditMessage.DataMessage.GroupV2 = groupMetadataForDataMessage(*group) content.EditMessage.DataMessage.GroupV2 = groupMetadataForDataMessage(*group)
} else if content.GetTypingMessage() != nil { case *signalpb.Content_TypingMessage:
messageTimestamp = content.TypingMessage.GetTimestamp() messageTimestamp = content.TypingMessage.GetTimestamp()
groupIDBytes, err := group.GroupIdentifier.Bytes() groupIDBytes, err := group.GroupIdentifier.Bytes()
if err != nil { if err != nil {
@ -606,7 +606,7 @@ func (cli *Client) sendToGroup(
FailedToSendTo: []FailedSendResult{}, FailedToSendTo: []FailedSendResult{},
} }
} }
if content.TypingMessage != nil { if content.GetTypingMessage() != nil {
// Never send typing messages via fallback path // Never send typing messages via fallback path
return result, nil return result, nil
} }
@ -648,15 +648,16 @@ func (cli *Client) sendToGroup(
func (cli *Client) sendGroupSyncCopy( func (cli *Client) sendGroupSyncCopy(
ctx context.Context, ctx context.Context,
content *signalpb.Content, rawContent *signalpb.Content,
messageTimestamp uint64, messageTimestamp uint64,
result *GroupMessageSendResult, result *GroupMessageSendResult,
groupID *libsignalgo.GroupIdentifier, groupID *libsignalgo.GroupIdentifier,
) { ) {
var syncContent *signalpb.Content var syncContent *signalpb.Content
if content.GetDataMessage() != nil { switch content := rawContent.Content.(type) {
case *signalpb.Content_DataMessage:
syncContent = syncMessageFromGroupDataMessage(content.DataMessage, result.SuccessfullySentTo) syncContent = syncMessageFromGroupDataMessage(content.DataMessage, result.SuccessfullySentTo)
} else if content.GetEditMessage() != nil { case *signalpb.Content_EditMessage:
syncContent = syncMessageFromGroupEditMessage(content.EditMessage, result.SuccessfullySentTo) syncContent = syncMessageFromGroupEditMessage(content.EditMessage, result.SuccessfullySentTo)
} }
if syncContent != nil { if syncContent != nil {
@ -667,16 +668,17 @@ func (cli *Client) sendGroupSyncCopy(
} }
} }
func (cli *Client) sendSyncCopy(ctx context.Context, content *signalpb.Content, messageTS uint64, result *SuccessfulSendResult) bool { func (cli *Client) sendSyncCopy(ctx context.Context, rawContent *signalpb.Content, messageTS uint64, result *SuccessfulSendResult) bool {
var syncContent *signalpb.Content var syncContent *signalpb.Content
if content.GetDataMessage() != nil { switch content := rawContent.Content.(type) {
case *signalpb.Content_DataMessage:
syncContent = syncMessageFromSoloDataMessage(content.DataMessage, *result) syncContent = syncMessageFromSoloDataMessage(content.DataMessage, *result)
} else if content.GetEditMessage() != nil { case *signalpb.Content_EditMessage:
syncContent = syncMessageFromSoloEditMessage(content.EditMessage, *result) syncContent = syncMessageFromSoloEditMessage(content.EditMessage, *result)
} else if content.GetReceiptMessage().GetType() == signalpb.ReceiptMessage_READ { case *signalpb.Content_ReceiptMessage:
syncContent = syncMessageFromReadReceiptMessage(ctx, content.ReceiptMessage, result.Recipient) syncContent = syncMessageFromReadReceiptMessage(ctx, content.ReceiptMessage, result.Recipient)
} else if content.GetSyncMessage() != nil { case *signalpb.Content_SyncMessage:
syncContent = content syncContent = rawContent
} }
if syncContent != nil { if syncContent != nil {
_, selfSendErr := cli.sendContent(ctx, cli.Store.ACIServiceID(), messageTS, syncContent, 0, true, nil, nil) _, selfSendErr := cli.sendContent(ctx, cli.Store.ACIServiceID(), messageTS, syncContent, 0, true, nil, nil)
@ -692,30 +694,33 @@ func (cli *Client) sendSyncCopy(ctx context.Context, content *signalpb.Content,
func (cli *Client) SendMessage(ctx context.Context, recipientID libsignalgo.ServiceID, content *signalpb.Content) SendMessageResult { func (cli *Client) SendMessage(ctx context.Context, recipientID libsignalgo.ServiceID, content *signalpb.Content) SendMessageResult {
// Assemble the content to send // Assemble the content to send
var messageTimestamp uint64 var messageTimestamp uint64
switch { switch realContent := content.Content.(type) {
case content.DataMessage != nil: case *signalpb.Content_DataMessage:
messageTimestamp = *content.DataMessage.Timestamp messageTimestamp = *realContent.DataMessage.Timestamp
case content.EditMessage != nil: case *signalpb.Content_EditMessage:
messageTimestamp = *content.EditMessage.DataMessage.Timestamp messageTimestamp = *realContent.EditMessage.DataMessage.Timestamp
case content.TypingMessage != nil: case *signalpb.Content_TypingMessage:
messageTimestamp = *content.TypingMessage.Timestamp messageTimestamp = *realContent.TypingMessage.Timestamp
case content.SyncMessage != nil, case *signalpb.Content_SyncMessage,
content.NullMessage != nil, *signalpb.Content_NullMessage,
content.ReceiptMessage != nil, *signalpb.Content_ReceiptMessage,
content.PniSignatureMessage != nil, *signalpb.Content_DecryptionErrorMessage:
content.SenderKeyDistributionMessage != nil,
content.DecryptionErrorMessage != nil:
messageTimestamp = currentMessageTimestamp() messageTimestamp = currentMessageTimestamp()
case *signalpb.Content_StoryMessage:
// not yet supported
default: default:
if content.SenderKeyDistributionMessage == nil && content.PniSignatureMessage == nil {
panic(fmt.Errorf("unsupported payload in SendMessage")) panic(fmt.Errorf("unsupported payload in SendMessage"))
} }
messageTimestamp = currentMessageTimestamp()
}
var aci, pni uuid.UUID var aci, pni uuid.UUID
if recipientID.Type == libsignalgo.ServiceIDTypeACI { if recipientID.Type == libsignalgo.ServiceIDTypeACI {
aci = recipientID.UUID aci = recipientID.UUID
} else if recipientID.Type == libsignalgo.ServiceIDTypePNI { } else if recipientID.Type == libsignalgo.ServiceIDTypePNI {
pni = recipientID.UUID pni = recipientID.UUID
} }
isTypingOrReceipt := content.TypingMessage != nil || content.ReceiptMessage != nil isTypingOrReceipt := content.GetTypingMessage() != nil || content.GetReceiptMessage() != nil
recipientData, err := cli.Store.RecipientStore.LoadAndUpdateRecipient(ctx, aci, pni, func(recipientData *types.Recipient) (changed bool, err error) { recipientData, err := cli.Store.RecipientStore.LoadAndUpdateRecipient(ctx, aci, pni, func(recipientData *types.Recipient) (changed bool, err error) {
if content.GetDataMessage().GetFlags() == uint32(signalpb.DataMessage_PROFILE_KEY_UPDATE) { if content.GetDataMessage().GetFlags() == uint32(signalpb.DataMessage_PROFILE_KEY_UPDATE) {
recipientData.Whitelisted = ptr.Ptr(true) recipientData.Whitelisted = ptr.Ptr(true)
@ -753,7 +758,7 @@ func (cli *Client) SendMessage(ctx context.Context, recipientID libsignalgo.Serv
cli.sendSyncCopy(ctx, content, messageTimestamp, &res) cli.sendSyncCopy(ctx, content, messageTimestamp, &res)
} }
return SendMessageResult{WasSuccessful: true, SuccessfulSendResult: res} return SendMessageResult{WasSuccessful: true, SuccessfulSendResult: res}
} else if content.TypingMessage != nil && cli.Store.DeviceData.AccountRecord != nil && !cli.Store.DeviceData.AccountRecord.GetTypingIndicators() { } else if content.GetTypingMessage() != nil && cli.Store.DeviceData.AccountRecord != nil && !cli.Store.DeviceData.AccountRecord.GetTypingIndicators() {
zerolog.Ctx(ctx).Debug().Msg("Not sending typing message as typing indicators are disabled") zerolog.Ctx(ctx).Debug().Msg("Not sending typing message as typing indicators are disabled")
res := SuccessfulSendResult{Recipient: recipientID} res := SuccessfulSendResult{Recipient: recipientID}
return SendMessageResult{WasSuccessful: true, SuccessfulSendResult: res} return SendMessageResult{WasSuccessful: true, SuccessfulSendResult: res}
@ -765,7 +770,7 @@ func (cli *Client) SendMessage(ctx context.Context, recipientID libsignalgo.Serv
return SendMessageResult{WasSuccessful: true, SuccessfulSendResult: res} return SendMessageResult{WasSuccessful: true, SuccessfulSendResult: res}
} }
isDeliveryReceipt := content.ReceiptMessage != nil && content.GetReceiptMessage().GetType() == signalpb.ReceiptMessage_DELIVERY isDeliveryReceipt := content.GetReceiptMessage() != nil && content.GetReceiptMessage().GetType() == signalpb.ReceiptMessage_DELIVERY
if recipientID == cli.Store.ACIServiceID() && !isDeliveryReceipt { if recipientID == cli.Store.ACIServiceID() && !isDeliveryReceipt {
res := SuccessfulSendResult{ res := SuccessfulSendResult{
Recipient: recipientID, Recipient: recipientID,
@ -819,26 +824,39 @@ func currentMessageTimestamp() uint64 {
} }
func isSyncMessageUrgent(content *signalpb.SyncMessage) bool { func isSyncMessageUrgent(content *signalpb.SyncMessage) bool {
return content.Sent != nil || content.Request != nil switch content.Content.(type) {
case *signalpb.SyncMessage_Request_,
*signalpb.SyncMessage_Sent_:
return true
default:
return false
}
} }
func isUrgent(content *signalpb.Content) bool { func isUrgent(rawContent *signalpb.Content) bool {
return content.DataMessage != nil || switch content := rawContent.Content.(type) {
content.CallMessage != nil || case *signalpb.Content_SyncMessage:
content.StoryMessage != nil || return isSyncMessageUrgent(content.SyncMessage)
content.EditMessage != nil || case *signalpb.Content_DataMessage,
(content.SyncMessage != nil && isSyncMessageUrgent(content.SyncMessage)) *signalpb.Content_EditMessage,
*signalpb.Content_CallMessage,
*signalpb.Content_StoryMessage:
return true
default:
return false
}
} }
func getContentHint(content *signalpb.Content) libsignalgo.UnidentifiedSenderMessageContentHint { func getContentHint(rawContent *signalpb.Content) libsignalgo.UnidentifiedSenderMessageContentHint {
if content.DataMessage != nil || content.EditMessage != nil { switch rawContent.Content.(type) {
case *signalpb.Content_DataMessage, *signalpb.Content_EditMessage:
return libsignalgo.UnidentifiedSenderMessageContentHintResendable return libsignalgo.UnidentifiedSenderMessageContentHintResendable
} case *signalpb.Content_TypingMessage, *signalpb.Content_ReceiptMessage:
if content.TypingMessage != nil || content.ReceiptMessage != nil {
return libsignalgo.UnidentifiedSenderMessageContentHintImplicit return libsignalgo.UnidentifiedSenderMessageContentHintImplicit
} default:
return libsignalgo.UnidentifiedSenderMessageContentHintDefault return libsignalgo.UnidentifiedSenderMessageContentHintDefault
} }
}
func (cli *Client) sendContent( func (cli *Client) sendContent(
ctx context.Context, ctx context.Context,
@ -858,12 +876,12 @@ func (cli *Client) sendContent(
ctx = log.WithContext(ctx) ctx = log.WithContext(ctx)
// If it's a data message, add our profile key // If it's a data message, add our profile key
if content.DataMessage != nil && content.DataMessage.ProfileKey == nil { if content.GetDataMessage() != nil && content.GetDataMessage().ProfileKey == nil {
profileKey, err := cli.ProfileKeyForSignalID(ctx, cli.Store.ACI) profileKey, err := cli.ProfileKeyForSignalID(ctx, cli.Store.ACI)
if err != nil { if err != nil {
log.Err(err).Msg("Error getting profile key, not adding to outgoing message") log.Err(err).Msg("Error getting profile key, not adding to outgoing message")
} else { } else {
content.DataMessage.ProfileKey = profileKey.Slice() content.GetDataMessage().ProfileKey = profileKey.Slice()
} }
} }

251
pkg/signalmeow/sticker.go Normal file
View file

@ -0,0 +1,251 @@
// 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

@ -66,12 +66,14 @@ func (cli *Client) processStorageInTxn(ctx context.Context, update *StorageUpdat
switch data := record.StorageRecord.GetRecord().(type) { switch data := record.StorageRecord.GetRecord().(type) {
case *signalpb.StorageRecord_Contact: case *signalpb.StorageRecord_Contact:
log.Trace().Any("contact_record", data.Contact).Msg("Handling contact record") log.Trace().Any("contact_record", data.Contact).Msg("Handling contact record")
aci, _ := uuid.Parse(data.Contact.Aci) aci, _ := ParseStringOrBinaryUUID(data.Contact.Aci, data.Contact.AciBinary)
pni, _ := uuid.Parse(data.Contact.Pni) pni, _ := ParseStringOrBinaryUUID(data.Contact.Pni, data.Contact.PniBinary)
if aci == uuid.Nil && pni == uuid.Nil { if aci == uuid.Nil && pni == uuid.Nil {
log.Warn(). log.Warn().
Str("raw_aci", data.Contact.Aci). Str("raw_aci", data.Contact.Aci).
Str("raw_pni", data.Contact.Pni). Str("raw_pni", data.Contact.Pni).
Hex("raw_aci_binary", data.Contact.AciBinary).
Hex("raw_pni_binary", data.Contact.PniBinary).
Str("raw_e164", data.Contact.E164). Str("raw_e164", data.Contact.E164).
Msg("Storage service has contact record with no ACI or PNI") Msg("Storage service has contact record with no ACI or PNI")
continue continue

View file

@ -28,6 +28,7 @@ import (
"net/http" "net/http"
"runtime" "runtime"
"strings" "strings"
"time"
"github.com/rs/zerolog" "github.com/rs/zerolog"
@ -129,6 +130,7 @@ 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)
@ -139,12 +141,14 @@ 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).Msg("Error sending request") log.Err(err).Dur("duration", dur).Msg("Error sending request")
return nil, err return nil, err
} }
log.Debug().Int("status_code", resp.StatusCode).Msg("received HTTP response") log.Debug().Int("status_code", resp.StatusCode).Dur("duration", dur).Msg("Received HTTP response")
return resp, nil return resp, nil
} }