mirror of
https://github.com/mautrix/signal.git
synced 2026-09-16 15:52:04 -04:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8771d18686 | ||
|
|
317b1687ec | ||
|
|
2541762364 | ||
|
|
2dbf8c051e | ||
|
|
74df702870 | ||
|
|
0981c89556 | ||
|
|
68d1d756bc | ||
|
|
4bbf143b1a | ||
|
|
3ee213518c | ||
|
|
f629397f45 | ||
|
|
6983c5ac68 | ||
|
|
268b4dbd33 | ||
|
|
4d2ea8381f | ||
|
|
43415e309b | ||
|
|
017e4b87dd | ||
|
|
210f3f2e0b | ||
|
|
5962e497e9 |
||
|
|
92d237af93 | ||
|
|
ee281f5a14 | ||
|
|
0d5f3f457d | ||
|
|
77a6664bc5 |
||
|
|
771150ee4a |
||
|
|
4eaacd6c56 |
||
|
|
8c7333a033 | ||
|
|
979d48aeb1 | ||
|
|
9142786157 | ||
|
|
542e5a3284 | ||
|
|
4f4f00423c | ||
|
|
3ddb32dd23 |
||
|
|
6e57bf3956 |
||
|
|
f25f588bc4 |
||
|
|
bed128ab84 | ||
|
|
4bbfe7e2cc |
167 changed files with 46400 additions and 5826 deletions
16
.github/workflows/go.yml
vendored
16
.github/workflows/go.yml
vendored
|
|
@ -11,14 +11,14 @@ jobs:
|
|||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
go-version: ["1.25", "1.26"]
|
||||
name: Lint ${{ matrix.go-version == '1.26' && '(latest)' || '(old)' }}
|
||||
go-version: ["1.26", "1.27"]
|
||||
name: Lint ${{ matrix.go-version == '1.27' && '(latest)' || '(old)' }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v6
|
||||
uses: actions/setup-go@v7
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
cache: true
|
||||
|
|
@ -40,14 +40,14 @@ jobs:
|
|||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
go-version: ["1.25", "1.26"]
|
||||
name: Test ${{ matrix.go-version == '1.26' && '(latest)' || '(old)' }}
|
||||
go-version: ["1.26", "1.27"]
|
||||
name: Test ${{ matrix.go-version == '1.27' && '(latest)' || '(old)' }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v6
|
||||
uses: actions/setup-go@v7
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
cache: true
|
||||
|
|
|
|||
16
CHANGELOG.md
16
CHANGELOG.md
|
|
@ -1,3 +1,19 @@
|
|||
# v26.09
|
||||
|
||||
* Bumped minimum Go version to 1.26.
|
||||
* Updated libsignal to v0.102.2.
|
||||
* Fixed handling messages with invalid values in formatting body ranges.
|
||||
* Fixed websocket request retrying not working correctly if the first attempt
|
||||
times out.
|
||||
* Fixed another potential race condition with edited message bridging.
|
||||
|
||||
# v26.08
|
||||
|
||||
* Updated libsignal to v0.100.0
|
||||
* Added support for handling own profile key changes.
|
||||
* Changed attachment bridging behavior to match Signal Desktop.
|
||||
* Fixed edited messages being bridged twice if certain race conditions occurred.
|
||||
|
||||
# v26.07
|
||||
|
||||
* Updated Docker image to Alpine 3.24.
|
||||
|
|
|
|||
1
CONTRIBUTING.md
Normal file
1
CONTRIBUTING.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
See <https://docs.mau.fi/bridges/general/contributing.html>
|
||||
|
|
@ -37,7 +37,7 @@ var m = mxmain.BridgeMain{
|
|||
Name: "mautrix-signal",
|
||||
URL: "https://github.com/mautrix/signal",
|
||||
Description: "A Matrix-Signal puppeting bridge.",
|
||||
Version: "26.07",
|
||||
Version: "26.09",
|
||||
SemCalVer: true,
|
||||
|
||||
Connector: &connector.SignalConnector{},
|
||||
|
|
|
|||
36
go.mod
36
go.mod
|
|
@ -1,8 +1,8 @@
|
|||
module go.mau.fi/mautrix-signal
|
||||
|
||||
go 1.25.0
|
||||
go 1.26.0
|
||||
|
||||
toolchain go1.26.5
|
||||
toolchain go1.27.1
|
||||
|
||||
tool go.mau.fi/util/cmd/maubuild
|
||||
|
||||
|
|
@ -12,40 +12,40 @@ require (
|
|||
github.com/google/uuid v1.6.0
|
||||
github.com/mattn/go-pointer v0.0.1
|
||||
github.com/rs/zerolog v1.35.1
|
||||
github.com/stretchr/testify v1.11.1
|
||||
github.com/stretchr/testify v1.12.0
|
||||
github.com/tidwall/gjson v1.19.0
|
||||
go.mau.fi/util v0.9.11
|
||||
golang.org/x/crypto v0.54.0
|
||||
golang.org/x/exp v0.0.0-20260709172345-9ea1abe57597
|
||||
golang.org/x/net v0.57.0
|
||||
golang.org/x/sync v0.22.0
|
||||
google.golang.org/protobuf v1.36.11
|
||||
go.mau.fi/util v0.10.1
|
||||
golang.org/x/crypto v0.57.0
|
||||
golang.org/x/exp v0.0.0-20260908205506-85c1c2202aba
|
||||
golang.org/x/net v0.59.0
|
||||
golang.org/x/sync v0.23.0
|
||||
google.golang.org/grpc v1.83.2
|
||||
google.golang.org/protobuf v1.36.12
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
maunium.net/go/mautrix v0.29.0
|
||||
maunium.net/go/mautrix v0.31.0
|
||||
)
|
||||
|
||||
require (
|
||||
filippo.io/edwards25519 v1.2.0 // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.7.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/kr/pretty v0.3.1 // indirect
|
||||
github.com/lib/pq v1.12.3 // indirect
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.14.48 // indirect
|
||||
github.com/petermattis/goid v0.0.0-20260713124913-97594f28f5ca // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.14.52 // indirect
|
||||
github.com/petermattis/goid v0.0.0-20260820044319-269ab09b5261 // indirect
|
||||
github.com/rogpeppe/go-internal v1.10.0 // indirect
|
||||
github.com/rs/xid v1.6.0 // indirect
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect
|
||||
github.com/tidwall/match v1.2.0 // indirect
|
||||
github.com/tidwall/pretty v1.2.1 // indirect
|
||||
github.com/tidwall/sjson v1.2.5 // indirect
|
||||
github.com/yuin/goldmark v1.8.4 // indirect
|
||||
github.com/yuin/goldmark v1.8.6 // indirect
|
||||
go.mau.fi/zeroconfig v0.2.0 // indirect
|
||||
golang.org/x/mod v0.38.0 // indirect
|
||||
golang.org/x/sys v0.47.0 // indirect
|
||||
golang.org/x/text v0.40.0 // indirect
|
||||
golang.org/x/mod v0.41.0 // indirect
|
||||
golang.org/x/sys v0.48.0 // indirect
|
||||
golang.org/x/text v0.42.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
|
||||
maunium.net/go/mauflag v1.0.0 // indirect
|
||||
|
|
|
|||
86
go.sum
86
go.sum
|
|
@ -2,15 +2,21 @@ filippo.io/edwards25519 v1.2.0 h1:crnVqOiS4jqYleHd9vaKZ+HKtHfllngJIiOpNpoJsjo=
|
|||
filippo.io/edwards25519 v1.2.0/go.mod h1:xzAOLCNug/yB62zG1bQ8uziwrIqIuxhctzJT18Q77mc=
|
||||
github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU=
|
||||
github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/coder/websocket v1.8.15 h1:6B2JPeOGlpff2Uz6vOEH1Vzpi0iUz20A+lPVhPHtNUA=
|
||||
github.com/coder/websocket v1.8.15/go.mod h1:NX3SzP+inril6yawo5CQXx8+fk145lPDC6pumgx0mVg=
|
||||
github.com/coreos/go-systemd/v22 v22.7.0 h1:LAEzFkke61DFROc7zNLX/WA2i5J8gYqe0rSj9KI28KA=
|
||||
github.com/coreos/go-systemd/v22 v22.7.0/go.mod h1:xNUYtjHu2EDXbsxz1i41wouACIwT7Ybq9o0BQhMwD0w=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/emersion/go-vcard v0.0.0-20241024213814-c9703dde27ff h1:4N8wnS3f1hNHSmFD5zgFkWCyA4L1kCDkImPAtK7D6tg=
|
||||
github.com/emersion/go-vcard v0.0.0-20241024213814-c9703dde27ff/go.mod h1:HMJKR5wlh/ziNp+sHEDV2ltblO4JD2+IdDOWtGcQBTM=
|
||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
|
|
@ -30,13 +36,11 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
|
|||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-pointer v0.0.1 h1:n+XhsuGeVO6MEAp7xyEukFINEa+Quek5psIR/ylA6o0=
|
||||
github.com/mattn/go-pointer v0.0.1/go.mod h1:2zXcozF6qYGgmsG+SeTZz3oAbFLdD3OWqnUbNvJZAlc=
|
||||
github.com/mattn/go-sqlite3 v1.14.48 h1:7XHIgl0a8HwOaiK4E47ozLkST78rR9+OtNGx27D/TFs=
|
||||
github.com/mattn/go-sqlite3 v1.14.48/go.mod h1:6JTjA44L93a0QCyJef5YvlPoKXntQPjzWv5gtm9sB6w=
|
||||
github.com/petermattis/goid v0.0.0-20260713124913-97594f28f5ca h1:GHSUVE4yOgX4E7kTRzpxCPbCOYkd3Kj8Dgdod30OI1E=
|
||||
github.com/petermattis/goid v0.0.0-20260713124913-97594f28f5ca/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4=
|
||||
github.com/mattn/go-sqlite3 v1.14.52 h1:wVbm2Qnf4OXkqhBTSPuCRZDRnxfbVrrmiCEroVdog8U=
|
||||
github.com/mattn/go-sqlite3 v1.14.52/go.mod h1:6JTjA44L93a0QCyJef5YvlPoKXntQPjzWv5gtm9sB6w=
|
||||
github.com/petermattis/goid v0.0.0-20260820044319-269ab09b5261 h1:lcWAnrqr2nNfDiArwFNHCE4787Mw2tCdVSOXCru0/0E=
|
||||
github.com/petermattis/goid v0.0.0-20260820044319-269ab09b5261/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4=
|
||||
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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
|
||||
|
|
@ -46,8 +50,8 @@ github.com/rs/zerolog v1.35.1 h1:m7xQeoiLIiV0BCEY4Hs+j2NG4Gp2o2KPKmhnnLiazKI=
|
|||
github.com/rs/zerolog v1.35.1/go.mod h1:EjML9kdfa/RMA7h/6z6pYmq1ykOuA8/mjWaEvGI+jcw=
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/stretchr/testify v1.12.0 h1:K6Mr6jO9JICuend/5xzTM03ydSV3vdNRYAdPSukj8uI=
|
||||
github.com/stretchr/testify v1.12.0/go.mod h1:bOYBZb5qJ00vPzWfIqBUZPaxK8jWiXc6d3ErP4Ca9Gw=
|
||||
github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/gjson v1.19.0 h1:xwxm7n691Uf3u5OFjzngavjGTh55KX5q/9w9xHW88JU=
|
||||
github.com/tidwall/gjson v1.19.0/go.mod h1:V37/opeE/JbLUOfH0QTXiNez2l0RUjYUhpT4szFQAfc=
|
||||
|
|
@ -59,29 +63,47 @@ github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
|
|||
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
|
||||
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
|
||||
github.com/yuin/goldmark v1.8.4 h1:oat/nd3U6NeQqFEL3xpEJq7d7c86NI+DbSNGAs4xnjA=
|
||||
github.com/yuin/goldmark v1.8.4/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg=
|
||||
go.mau.fi/util v0.9.11 h1:Cus1Lu/t7d3OG6VF4aYWvlUUS0Q4O1/lcpPNJZ0jsw0=
|
||||
go.mau.fi/util v0.9.11/go.mod h1:xunp/oIQfFD68HHcNHfG0pOiHkvEtDhTweeIwKJ//+Q=
|
||||
github.com/yuin/goldmark v1.8.6 h1:d0VcaP1sx9GkFVkoW+KtggpGi2KZ965i14b0+bDQST4=
|
||||
github.com/yuin/goldmark v1.8.6/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg=
|
||||
go.mau.fi/util v0.10.1 h1:1oSqb4TwzLA0cUDY0aomyBPFKkZ3J5fqCmrXV3VH3GQ=
|
||||
go.mau.fi/util v0.10.1/go.mod h1:40TDo7/ekSeOjgr8KAmX31Yf4zrOF94j83WQB+u5ZPc=
|
||||
go.mau.fi/zeroconfig v0.2.0 h1:e/OGEERqVRRKlgaro7E6bh8xXiKFSXB3eNNIud7FUjU=
|
||||
go.mau.fi/zeroconfig v0.2.0/go.mod h1:J0Vn0prHNOm493oZoQ84kq83ZaNCYZnq+noI1b1eN8w=
|
||||
golang.org/x/crypto v0.54.0 h1:YLIA59K4fiNzHzjnZt2tUJQjQtUWfWbeHBqKtk3eScw=
|
||||
golang.org/x/crypto v0.54.0/go.mod h1:KWL8ny2AZdGR2cWmzeHrp2azQPGogOv+HeQaVEXC2dk=
|
||||
golang.org/x/exp v0.0.0-20260709172345-9ea1abe57597 h1:qLvzZeaANDgyVOA8pyHCOStGlXn0rseXma+GQjeuv2g=
|
||||
golang.org/x/exp v0.0.0-20260709172345-9ea1abe57597/go.mod h1:EdfpwwqSu+0Li0mzskwHU6FWDV3t9Q+RZDo3QMUtL3Q=
|
||||
golang.org/x/mod v0.38.0 h1:MECBjubtXD7yj4HrhIUcywNaGeNVUdfVnxmPajOk4yk=
|
||||
golang.org/x/mod v0.38.0/go.mod h1:V6Xz0pq8TQ3dGqVQ1FVHuelZpAL0uNhSkk9ogYP3c40=
|
||||
golang.org/x/net v0.57.0 h1:K5+3DljvIuDG9/Jv9rvyMywYNFCQ9RSUY6OOTTkT+tE=
|
||||
golang.org/x/net v0.57.0/go.mod h1:KpXc8iv+r3XplLAG/f7Jsf9RPszJzdR0f58q9vGOuEU=
|
||||
golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek=
|
||||
golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||
go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU=
|
||||
go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc=
|
||||
go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc=
|
||||
go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo=
|
||||
go.opentelemetry.io/otel/sdk v1.44.0 h1:nHYwb9lK+fJPU/dnT6s7W7Z8itMWyqrnVfbheVYrZ58=
|
||||
go.opentelemetry.io/otel/sdk v1.44.0/go.mod h1:Osuydd3Se74nqjAKxid74N5eC+jfEqfTegHRnq58oK0=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.44.0 h1:3LlKgI+VjbVsjNRFZJZAJ30WjXC5VkNRks6si09iEfI=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.44.0/go.mod h1:5B5pMARnXxKhltooO4xUuCBorl65a4EpnTalObqOigA=
|
||||
go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk=
|
||||
go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE=
|
||||
golang.org/x/crypto v0.57.0 h1:3ZVCjf8Ggz7zneR/EHRVx68Ctf+2pmIMP2UFhh9cC6M=
|
||||
golang.org/x/crypto v0.57.0/go.mod h1:Fdz0i5U6CoizGwLda9DttjSk6qlZo25zYNtR+ycvuZA=
|
||||
golang.org/x/exp v0.0.0-20260908205506-85c1c2202aba h1:Ck8QetSgk912qxWLMCKxd0in+aiyBQyDSMae6e/xmpU=
|
||||
golang.org/x/exp v0.0.0-20260908205506-85c1c2202aba/go.mod h1:50RgIsmK7OwqzTTeqcSXQW8SswW0o8fRcDxmqGluJ8E=
|
||||
golang.org/x/mod v0.41.0 h1:qJmnOUb4YB+FsEuM3HcWucdZASCPGhsX6uljO6pog0c=
|
||||
golang.org/x/mod v0.41.0/go.mod h1:Ek9pY8RKWXwsWvd3rQiHYtMqkjSUV+s1Rj7j4H5Ur6o=
|
||||
golang.org/x/net v0.59.0 h1:5zfYln+w5XCxwrnMMJPufRgNoXEaGxl0wo5GqPXyues=
|
||||
golang.org/x/net v0.59.0/go.mod h1:2DA/G1UfVbCpQPeWTmMPGY7Cs2PkBkwu743bVX5PIVg=
|
||||
golang.org/x/sync v0.23.0 h1:KameEIfc1IkluZyXWLn39Wd4tURc6GbCiISGiZm2bQk=
|
||||
golang.org/x/sync v0.23.0/go.mod h1:sUUOizhqBxiL6pEWpqNLUiaJn1ShEbZ6BBqskPbjZm0=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs=
|
||||
golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/text v0.40.0 h1:Ub2Z6/xjgF1WrYQz2nuITOEegKFtiIy+rieRJ5lHZKs=
|
||||
golang.org/x/text v0.40.0/go.mod h1:hpnzDAfGV753zIKo+wk3u1bVKCGPbrnF7+7LBF/UHVY=
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
golang.org/x/sys v0.48.0 h1:bbX/i/6MgT9BVLM9RT1thmxL04yeTAhbEz4SyadbXoo=
|
||||
golang.org/x/sys v0.48.0/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og=
|
||||
golang.org/x/text v0.42.0 h1:JbOZXgfeCPU9gacVtYliJqOhD+zhrEqK4LfdpmlUZqI=
|
||||
golang.org/x/text v0.42.0/go.mod h1:ojzP1Z+2QtioaF8DTtO8K5q7JWVVYwZKenzujK0Zd0E=
|
||||
gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
|
||||
gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa h1:mZHHdPZl0dbGHCflZgAq/Q468DWVFcU2whhB2KAo8fk=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||
google.golang.org/grpc v1.83.2 h1:EManeRomTObA0BU7I8vXgg/78uE5MJ9M8B39EX2WscU=
|
||||
google.golang.org/grpc v1.83.2/go.mod h1:YPI1hK3kDked6iHvgX3tR0y+nX/qpMFKhPgFsokw1S8=
|
||||
google.golang.org/protobuf v1.36.12 h1:pJOKDDOyeXErUroCihFAd5LQuwXBSpVnKGrj5o/fwxc=
|
||||
google.golang.org/protobuf v1.36.12/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
|
|
@ -91,5 +113,5 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
|||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
maunium.net/go/mauflag v1.0.0 h1:YiaRc0tEI3toYtJMRIfjP+jklH45uDHtT80nUamyD4M=
|
||||
maunium.net/go/mauflag v1.0.0/go.mod h1:nLivPOpTpHnpzEh8jEdSL9UqO9+/KBJFmNRlwKfkPeA=
|
||||
maunium.net/go/mautrix v0.29.0 h1:OkcBJF1dvp+93EgahxMxOUZZOrGTYculI9IprvRIMOQ=
|
||||
maunium.net/go/mautrix v0.29.0/go.mod h1:LynuVr8N9nWsE1N4WAE+vItRACDB1pt9M3gN4SIBpeY=
|
||||
maunium.net/go/mautrix v0.31.0 h1:x6XNBSa0kOaBgcleI+ZBLkGvBdHIE0qdeY6TZ4wWUeI=
|
||||
maunium.net/go/mautrix v0.31.0/go.mod h1:vfPYtoGAjlTnIF+W8tl+rjX3yB4PEfqYR2sDXvQo4Co=
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ func supportedIfFFmpeg() event.CapabilitySupportLevel {
|
|||
}
|
||||
|
||||
func capID() string {
|
||||
base := "fi.mau.signal.capabilities.2026_07_14"
|
||||
base := "fi.mau.signal.capabilities.2026_07_22"
|
||||
if ffmpeg.Supported() {
|
||||
return base + "+ffmpeg"
|
||||
}
|
||||
|
|
@ -77,6 +77,7 @@ var signalCaps = &event.RoomFeatures{
|
|||
"image/jpeg": event.CapLevelFullySupported,
|
||||
"image/webp": event.CapLevelFullySupported,
|
||||
"image/bmp": event.CapLevelFullySupported,
|
||||
"image/avif": event.CapLevelFullySupported,
|
||||
},
|
||||
MaxWidth: 4096,
|
||||
MaxHeight: 4096,
|
||||
|
|
@ -98,6 +99,8 @@ var signalCaps = &event.RoomFeatures{
|
|||
MimeTypes: map[string]event.CapabilitySupportLevel{
|
||||
"audio/aac": event.CapLevelFullySupported,
|
||||
"audio/mpeg": event.CapLevelFullySupported,
|
||||
"audio/mp3": event.CapLevelFullySupported,
|
||||
"audio/flac": event.CapLevelFullySupported,
|
||||
},
|
||||
MaxSize: MaxFileSize,
|
||||
},
|
||||
|
|
@ -151,18 +154,23 @@ var signalCaps = &event.RoomFeatures{
|
|||
event.MemberActionBan: event.CapLevelFullySupported,
|
||||
event.MemberActionKick: event.CapLevelFullySupported,
|
||||
},
|
||||
MaxTextLength: MaxTextLength, // TODO support arbitrary sized text messages with files
|
||||
LocationMessage: event.CapLevelPartialSupport,
|
||||
Poll: event.CapLevelFullySupported,
|
||||
Thread: event.CapLevelUnsupported,
|
||||
Reply: event.CapLevelFullySupported,
|
||||
Edit: event.CapLevelFullySupported,
|
||||
EditMaxCount: 10,
|
||||
EditMaxAge: ptr.Ptr(jsontime.S(24 * time.Hour)),
|
||||
Delete: event.CapLevelFullySupported,
|
||||
DeleteForMe: false,
|
||||
DeleteMaxAge: ptr.Ptr(jsontime.S(24 * time.Hour)),
|
||||
DisappearingTimer: signalDisappearingCap,
|
||||
MaxTextLength: MaxTextLength, // TODO support arbitrary sized text messages with files
|
||||
LocationMessage: event.CapLevelPartialSupport,
|
||||
Poll: event.CapLevelFullySupported,
|
||||
PollEnd: event.CapLevelUnsupported,
|
||||
PollHiddenVotes: event.CapLevelUnsupported,
|
||||
PollDuplicateOptions: event.CapLevelFullySupported,
|
||||
PollMaxOptions: 10,
|
||||
PollOptionMaxLength: 100,
|
||||
Thread: event.CapLevelUnsupported,
|
||||
Reply: event.CapLevelFullySupported,
|
||||
Edit: event.CapLevelFullySupported,
|
||||
EditMaxCount: 10,
|
||||
EditMaxAge: ptr.Ptr(jsontime.S(24 * time.Hour)),
|
||||
Delete: event.CapLevelFullySupported,
|
||||
DeleteForMe: false,
|
||||
DeleteMaxAge: ptr.Ptr(jsontime.S(24 * time.Hour)),
|
||||
DisappearingTimer: signalDisappearingCap,
|
||||
|
||||
Reaction: event.CapLevelFullySupported,
|
||||
ReactionCount: 1,
|
||||
|
|
@ -237,5 +245,5 @@ func (s *SignalConnector) GetCapabilities() *bridgev2.NetworkGeneralCapabilities
|
|||
}
|
||||
|
||||
func (s *SignalConnector) GetBridgeInfoVersion() (info, capabilities int) {
|
||||
return 1, 9
|
||||
return 1, 11
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ import (
|
|||
"go.mau.fi/mautrix-signal/pkg/libsignalgo"
|
||||
"go.mau.fi/mautrix-signal/pkg/signalid"
|
||||
"go.mau.fi/mautrix-signal/pkg/signalmeow"
|
||||
signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf"
|
||||
"go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf/signalpb"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -180,12 +180,48 @@ func (s *SignalClient) HandleMatrixEdit(ctx context.Context, msg *bridgev2.Matri
|
|||
if err != nil {
|
||||
return bridgev2.WrapErrorInStatus(err).WithSendNotice(true)
|
||||
}
|
||||
prevID := msg.EditTarget.ID
|
||||
msg.EditTarget.ID = signalid.MakeMessageID(s.Client.Store.ACI, ts)
|
||||
msg.EditTarget.Metadata = &signalid.MessageMetadata{ContainsAttachments: len(converted.Attachments) > 0}
|
||||
msg.EditTarget.EditCount++
|
||||
if prevID != msg.EditTarget.ID {
|
||||
err = s.Main.Bridge.DB.DoTxn(ctx, nil, func(ctx context.Context) error {
|
||||
err = s.Main.Bridge.DB.Message.Update(ctx, msg.EditTarget)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = saveEditStub(ctx, s.Main.Bridge, prevID, msg.EditTarget)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to save edit stub: %w", err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
zerolog.Ctx(ctx).Err(err).
|
||||
Str("prev_message_id", string(prevID)).
|
||||
Str("message_id", string(msg.EditTarget.ID)).
|
||||
Msg("Failed to save message after editing")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// saveEditStub saves a placeholder message row pointing at the pre-edit ID of a message, such that
|
||||
// duplicate checks on incoming edits find it and are dropped. This is necessary because the first
|
||||
// time we see an edit it modifies the ID in place.
|
||||
func saveEditStub(ctx context.Context, bridge *bridgev2.Bridge, prevID networkid.MessageID, target *database.Message) error {
|
||||
stub := &database.Message{
|
||||
ID: prevID,
|
||||
PartID: editStubPartID,
|
||||
Room: target.Room,
|
||||
SenderID: target.SenderID,
|
||||
SenderMXID: target.SenderMXID,
|
||||
Timestamp: target.Timestamp,
|
||||
}
|
||||
stub.SetFakeMXID()
|
||||
return bridge.DB.Message.Insert(ctx, stub)
|
||||
}
|
||||
|
||||
func (s *SignalClient) PreHandleMatrixReaction(ctx context.Context, msg *bridgev2.MatrixReaction) (bridgev2.MatrixReactionPreResponse, error) {
|
||||
return bridgev2.MatrixReactionPreResponse{
|
||||
SenderID: signalid.MakeUserID(s.Client.Store.ACI),
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import (
|
|||
"context"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
|
@ -39,7 +40,7 @@ import (
|
|||
"go.mau.fi/mautrix-signal/pkg/signalid"
|
||||
"go.mau.fi/mautrix-signal/pkg/signalmeow"
|
||||
"go.mau.fi/mautrix-signal/pkg/signalmeow/events"
|
||||
signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf"
|
||||
"go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf/signalpb"
|
||||
"go.mau.fi/mautrix-signal/pkg/signalmeow/types"
|
||||
)
|
||||
|
||||
|
|
@ -358,20 +359,52 @@ func (evt *Bv2ChatEvent) ConvertMessage(ctx context.Context, portal *bridgev2.Po
|
|||
return converted, nil
|
||||
}
|
||||
|
||||
const editStubPartID networkid.PartID = "editstub"
|
||||
|
||||
func isEditStub(msg *database.Message) bool {
|
||||
return msg.PartID == editStubPartID
|
||||
}
|
||||
|
||||
// editStubMessage returns a non-bridged message part which is saved as a placeholder row pointing
|
||||
// at the pre-edit ID of a message, such that duplicate checks on incoming edits find it and are
|
||||
// dropped. This is necessary because the first time we see an edit it modifies the ID in place.
|
||||
func editStubMessage() *bridgev2.ConvertedMessage {
|
||||
return &bridgev2.ConvertedMessage{
|
||||
Parts: []*bridgev2.ConvertedMessagePart{{
|
||||
ID: editStubPartID,
|
||||
Type: event.EventMessage,
|
||||
Content: &event.MessageEventContent{},
|
||||
DontBridge: true,
|
||||
}},
|
||||
}
|
||||
}
|
||||
|
||||
func (evt *Bv2ChatEvent) ConvertEdit(ctx context.Context, portal *bridgev2.Portal, intent bridgev2.MatrixAPI, existing []*database.Message) (*bridgev2.ConvertedEdit, error) {
|
||||
editMsg, ok := evt.Event.(*signalpb.EditMessage)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("ConvertEdit() called for non-EditMessage event")
|
||||
}
|
||||
existing = slices.DeleteFunc(slices.Clone(existing), isEditStub)
|
||||
if len(existing) == 0 {
|
||||
return nil, fmt.Errorf("%w: edit target has already been edited", bridgev2.ErrIgnoringRemoteEvent)
|
||||
}
|
||||
// TODO tell converter about existing parts to avoid reupload?
|
||||
converted := evt.s.Main.MsgConv.ToMatrix(ctx, evt.s.Client, portal, evt.Info.Sender, intent, editMsg.GetDataMessage(), nil)
|
||||
// TODO can anything other than the text be edited?
|
||||
editPart := converted.Parts[len(converted.Parts)-1].ToEditPart(existing[len(existing)-1])
|
||||
prevID := editPart.Part.ID
|
||||
// Clone the database message struct to avoid mutating the ID.
|
||||
// The ID from the original struct is used for AddedParts (we specifically want the old ID for that)
|
||||
editPart.Part = ptr.Clone(editPart.Part)
|
||||
editPart.Part.EditCount++
|
||||
editPart.Part.ID = signalid.MakeMessageID(evt.Info.Sender, editMsg.GetDataMessage().GetTimestamp())
|
||||
return &bridgev2.ConvertedEdit{
|
||||
convertedEdit := &bridgev2.ConvertedEdit{
|
||||
ModifiedParts: []*bridgev2.ConvertedEditPart{editPart},
|
||||
}, nil
|
||||
}
|
||||
if prevID != editPart.Part.ID {
|
||||
convertedEdit.AddedParts = editStubMessage()
|
||||
}
|
||||
return convertedEdit, nil
|
||||
}
|
||||
|
||||
func (evt *Bv2ChatEvent) GetStreamOrder() int64 {
|
||||
|
|
|
|||
|
|
@ -18,9 +18,12 @@ package connector
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/coder/websocket"
|
||||
"github.com/google/uuid"
|
||||
"maunium.net/go/mautrix/bridgev2"
|
||||
"maunium.net/go/mautrix/bridgev2/database"
|
||||
|
|
@ -41,7 +44,7 @@ func (s *SignalConnector) GetLoginFlows() []bridgev2.LoginFlow {
|
|||
|
||||
func (s *SignalConnector) CreateLogin(ctx context.Context, user *bridgev2.User, flowID string) (bridgev2.LoginProcess, error) {
|
||||
if flowID != "qr" {
|
||||
return nil, fmt.Errorf("invalid login flow ID")
|
||||
return nil, bridgev2.ErrInvalidLoginFlowID
|
||||
}
|
||||
return &QRLogin{User: user, Main: s}, nil
|
||||
}
|
||||
|
|
@ -66,10 +69,78 @@ func (qr *QRLogin) Cancel() {
|
|||
|
||||
const (
|
||||
LoginStepQR = "fi.mau.signal.login.qr"
|
||||
LoginStepProcess = "fi.mau.signal.login.processing"
|
||||
LoginStepComplete = "fi.mau.signal.login.complete"
|
||||
)
|
||||
|
||||
const (
|
||||
qrRefreshInterval = 45 * time.Second
|
||||
maxQRRefreshes = 20
|
||||
)
|
||||
|
||||
var (
|
||||
ErrLoginTimedOut = bridgev2.RespError{
|
||||
ErrCode: "FI.MAU.BRIDGE.LOGIN_TIMED_OUT",
|
||||
Err: "The QR code wasn't scanned in time, please start a new login",
|
||||
StatusCode: http.StatusGone,
|
||||
}
|
||||
ErrLoginCancelled = bridgev2.RespError{
|
||||
ErrCode: "FI.MAU.BRIDGE.LOGIN_CANCELLED",
|
||||
Err: "Login process was cancelled",
|
||||
StatusCode: http.StatusGone,
|
||||
}
|
||||
ErrDeviceLinkMissingCapability = bridgev2.RespError{
|
||||
ErrCode: "FI.MAU.SIGNAL.DEVICE_LINK_MISSING_CAPABILITY",
|
||||
Err: "Signal rejected linking because the bridge is missing a capability required by your account's other devices. Please try again later",
|
||||
StatusCode: http.StatusConflict,
|
||||
}
|
||||
ErrDeviceLimitReached = bridgev2.RespError{
|
||||
ErrCode: "FI.MAU.SIGNAL.DEVICE_LIMIT_REACHED",
|
||||
Err: "Your Signal account already has the maximum number of linked devices. Remove one in the Signal app and try again",
|
||||
StatusCode: http.StatusBadRequest,
|
||||
}
|
||||
ErrDeviceLinkCodeInvalid = bridgev2.RespError{
|
||||
ErrCode: "FI.MAU.SIGNAL.DEVICE_LINK_CODE_INVALID",
|
||||
Err: "The scanned QR code was invalid or already used, please start a new login",
|
||||
StatusCode: http.StatusForbidden,
|
||||
}
|
||||
ErrDeviceLinkRateLimited = bridgev2.RespError{
|
||||
ErrCode: "FI.MAU.SIGNAL.DEVICE_LINK_RATE_LIMITED",
|
||||
Err: "Signal rate-limited the linking attempt, please wait a few minutes and try again",
|
||||
StatusCode: http.StatusTooManyRequests,
|
||||
}
|
||||
ErrDeviceLinkRejected = bridgev2.RespError{
|
||||
ErrCode: "FI.MAU.SIGNAL.DEVICE_LINK_REJECTED",
|
||||
Err: "Signal rejected linking the device",
|
||||
StatusCode: http.StatusBadRequest,
|
||||
}
|
||||
)
|
||||
|
||||
// Statuses of PUT /v1/devices/link, per Signal-Server's DeviceController
|
||||
func wrapProvisioningError(err error) error {
|
||||
var linkErr signalmeow.DeviceLinkError
|
||||
if errors.As(err, &linkErr) {
|
||||
switch linkErr.StatusCode {
|
||||
case http.StatusConflict:
|
||||
return ErrDeviceLinkMissingCapability
|
||||
case http.StatusLengthRequired:
|
||||
return ErrDeviceLimitReached
|
||||
case http.StatusForbidden:
|
||||
return ErrDeviceLinkCodeInvalid
|
||||
case http.StatusTooManyRequests:
|
||||
return ErrDeviceLinkRateLimited
|
||||
default:
|
||||
if linkErr.Message != "" {
|
||||
return ErrDeviceLinkRejected.AppendMessage(" (HTTP %d: %s)", linkErr.StatusCode, linkErr.Message)
|
||||
}
|
||||
return ErrDeviceLinkRejected.AppendMessage(" (HTTP %d)", linkErr.StatusCode)
|
||||
}
|
||||
}
|
||||
if websocket.CloseStatus(err) == websocket.StatusGoingAway {
|
||||
return ErrLoginTimedOut
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (qr *QRLogin) Start(ctx context.Context) (*bridgev2.LoginStep, error) {
|
||||
log := qr.Main.Bridge.Log.With().
|
||||
Str("action", "login").
|
||||
|
|
@ -85,14 +156,16 @@ func (qr *QRLogin) Start(ctx context.Context) (*bridgev2.LoginStep, error) {
|
|||
select {
|
||||
case resp = <-qr.ProvChan:
|
||||
if resp.Err != nil {
|
||||
return nil, resp.Err
|
||||
return nil, wrapProvisioningError(resp.Err)
|
||||
} else if resp.State != signalmeow.StateProvisioningURLReceived {
|
||||
return nil, fmt.Errorf("unexpected state %v", resp.State)
|
||||
}
|
||||
case <-ctx.Done():
|
||||
cancel()
|
||||
return nil, ctx.Err()
|
||||
// TODO separate timeout here?
|
||||
if errors.Is(ctx.Err(), context.DeadlineExceeded) {
|
||||
return nil, ErrLoginTimedOut
|
||||
}
|
||||
return nil, ErrLoginCancelled
|
||||
}
|
||||
return &bridgev2.LoginStep{
|
||||
Type: bridgev2.LoginStepTypeDisplayAndWait,
|
||||
|
|
@ -114,7 +187,7 @@ func (qr *QRLogin) Wait(ctx context.Context) (*bridgev2.LoginStep, error) {
|
|||
case resp := <-qr.ProvChan:
|
||||
if resp.Err != nil {
|
||||
qr.cancelChan()
|
||||
return nil, resp.Err
|
||||
return nil, wrapProvisioningError(resp.Err)
|
||||
} else if resp.State != signalmeow.StateProvisioningDataReceived {
|
||||
qr.cancelChan()
|
||||
return nil, fmt.Errorf("unexpected state %v", resp.State)
|
||||
|
|
@ -126,17 +199,20 @@ func (qr *QRLogin) Wait(ctx context.Context) (*bridgev2.LoginStep, error) {
|
|||
|
||||
// Server will timeout the request after 60 seconds, but Signal Desktop opens
|
||||
// a new socket and gets a new QR code after 45 seconds. We should do the same.
|
||||
case <-time.After(45 * time.Second):
|
||||
case <-time.After(qrRefreshInterval):
|
||||
qr.cancelChan()
|
||||
qr.newQRCount++
|
||||
if qr.newQRCount >= 6 {
|
||||
return nil, fmt.Errorf("too many QR code refreshes")
|
||||
if qr.newQRCount >= maxQRRefreshes {
|
||||
return nil, ErrLoginTimedOut
|
||||
}
|
||||
return qr.Start(ctx)
|
||||
|
||||
case <-ctx.Done():
|
||||
qr.cancelChan()
|
||||
return nil, ctx.Err()
|
||||
if errors.Is(ctx.Err(), context.DeadlineExceeded) {
|
||||
return nil, ErrLoginTimedOut
|
||||
}
|
||||
return nil, ErrLoginCancelled
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,19 +20,17 @@ package libsignalgo
|
|||
#include "./libsignal-ffi.h"
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"runtime"
|
||||
"unsafe"
|
||||
)
|
||||
import "runtime"
|
||||
|
||||
type AccountEntropyPool string
|
||||
type SVRKey = fixedArray32
|
||||
|
||||
func (aep AccountEntropyPool) DeriveSVRKey() ([]byte, error) {
|
||||
var out [C.SignalSVR_KEY_LEN]byte
|
||||
var out SVRKey
|
||||
aepC, free := GoStringToCString(string(aep))
|
||||
defer free()
|
||||
signalFfiError := C.signal_account_entropy_pool_derive_svr_key(
|
||||
(*[C.SignalSVR_KEY_LEN]C.uint8_t)(unsafe.Pointer(&out)),
|
||||
out.cFixedArray(),
|
||||
aepC,
|
||||
)
|
||||
runtime.KeepAlive(aep)
|
||||
|
|
@ -43,11 +41,11 @@ func (aep AccountEntropyPool) DeriveSVRKey() ([]byte, error) {
|
|||
}
|
||||
|
||||
func (aep AccountEntropyPool) DeriveBackupKey() ([]byte, error) {
|
||||
var out [C.SignalBACKUP_KEY_LEN]byte
|
||||
var out BackupKey
|
||||
aepC, free := GoStringToCString(string(aep))
|
||||
defer free()
|
||||
signalFfiError := C.signal_account_entropy_pool_derive_backup_key(
|
||||
(*[C.SignalBACKUP_KEY_LEN]C.uint8_t)(unsafe.Pointer(&out)),
|
||||
out.cFixedArray(),
|
||||
aepC,
|
||||
)
|
||||
runtime.KeepAlive(aep)
|
||||
|
|
|
|||
|
|
@ -82,6 +82,7 @@ func (aes *AES256_GCM_SIV) Decrypt(ciphertext, nonce, associatedData []byte) ([]
|
|||
BytesToBuffer(nonce),
|
||||
BytesToBuffer(associatedData),
|
||||
)
|
||||
runtime.KeepAlive(aes)
|
||||
if signalFfiError != nil {
|
||||
return nil, wrapError(signalFfiError)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,15 +24,17 @@ package libsignalgo
|
|||
import "C"
|
||||
import (
|
||||
"fmt"
|
||||
"unsafe"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// type AuthCredential [C.SignalAUTH_CREDENTIAL_LEN]byte
|
||||
// type AuthCredentialResponse [C.SignalAUTH_CREDENTIAL_RESPONSE_LEN]byte
|
||||
type AuthCredentialWithPni [C.SignalAUTH_CREDENTIAL_WITH_PNI_LEN]byte
|
||||
type AuthCredentialWithPniResponse [C.SignalAUTH_CREDENTIAL_WITH_PNI_RESPONSE_LEN]byte
|
||||
// type AuthCredential [181]byte
|
||||
// type AuthCredentialResponse [361]byte
|
||||
const AuthCredentialWithPniLength = 265
|
||||
const AuthCredentialWithPniResponseLength = 425
|
||||
|
||||
type AuthCredentialWithPni [AuthCredentialWithPniLength]byte
|
||||
type AuthCredentialWithPniResponse [AuthCredentialWithPniResponseLength]byte
|
||||
type AuthCredentialPresentation []byte
|
||||
|
||||
func (ac *AuthCredentialWithPni) Slice() []byte {
|
||||
|
|
@ -51,8 +53,8 @@ func ReceiveAuthCredentialWithPni(
|
|||
signalFfiError := C.signal_server_public_params_receive_auth_credential_with_pni_as_service_id(
|
||||
&c_result,
|
||||
C.SignalConstPointerServerPublicParams{serverPublicParams},
|
||||
NewACIServiceID(aci).CFixedBytes(),
|
||||
NewPNIServiceID(pni).CFixedBytes(),
|
||||
NewACIServiceID(aci).cConstFixedArray(),
|
||||
NewPNIServiceID(pni).cConstFixedArray(),
|
||||
C.uint64_t(redemptionTime),
|
||||
BytesToBuffer(authCredResponse[:]),
|
||||
)
|
||||
|
|
@ -60,13 +62,16 @@ func ReceiveAuthCredentialWithPni(
|
|||
return nil, wrapError(signalFfiError)
|
||||
}
|
||||
resultBytes := CopySignalOwnedBufferToBytes(c_result)
|
||||
if len(resultBytes) != C.SignalAUTH_CREDENTIAL_WITH_PNI_LEN {
|
||||
return nil, fmt.Errorf("invalid response length %d (expected %d)", len(resultBytes), C.SignalAUTH_CREDENTIAL_WITH_PNI_LEN)
|
||||
if len(resultBytes) != AuthCredentialWithPniLength {
|
||||
return nil, fmt.Errorf("invalid response length %d (expected %d)", len(resultBytes), AuthCredentialWithPniLength)
|
||||
}
|
||||
return (*AuthCredentialWithPni)(resultBytes), nil
|
||||
}
|
||||
|
||||
func NewAuthCredentialWithPniResponse(b []byte) (*AuthCredentialWithPniResponse, error) {
|
||||
if len(b) != AuthCredentialWithPniResponseLength {
|
||||
return nil, fmt.Errorf("invalid auth credential with pni response length %d (expected %d)", len(b), AuthCredentialWithPniResponseLength)
|
||||
}
|
||||
borrowedBuffer := BytesToBuffer(b)
|
||||
signalFfiError := C.signal_auth_credential_with_pni_response_check_valid_contents(borrowedBuffer)
|
||||
if signalFfiError != nil {
|
||||
|
|
@ -83,14 +88,12 @@ func CreateAuthCredentialWithPniPresentation(
|
|||
authCredWithPni AuthCredentialWithPni,
|
||||
) (*AuthCredentialPresentation, error) {
|
||||
var c_result C.SignalOwnedBuffer = C.SignalOwnedBuffer{}
|
||||
c_randomness := (*[C.SignalRANDOMNESS_LEN]C.uchar)(unsafe.Pointer(&randomness[0]))
|
||||
c_groupSecretParams := (*[C.SignalGROUP_SECRET_PARAMS_LEN]C.uchar)(unsafe.Pointer(&groupSecretParams[0]))
|
||||
|
||||
signalFfiError := C.signal_server_public_params_create_auth_credential_with_pni_presentation_deterministic(
|
||||
&c_result,
|
||||
C.SignalConstPointerServerPublicParams{serverPublicParams},
|
||||
c_randomness,
|
||||
c_groupSecretParams,
|
||||
randomness.cConstFixedArray(),
|
||||
groupSecretParams.cConstFixedArray(),
|
||||
BytesToBuffer(authCredWithPni[:]),
|
||||
)
|
||||
if signalFfiError != nil {
|
||||
|
|
|
|||
|
|
@ -27,7 +27,9 @@ import (
|
|||
"go.mau.fi/util/random"
|
||||
)
|
||||
|
||||
type BackupKey [C.SignalBACKUP_KEY_LEN]byte
|
||||
const BackupKeyLength = 32
|
||||
|
||||
type BackupKey [BackupKeyLength]byte
|
||||
|
||||
func (bk *BackupKey) Slice() []byte {
|
||||
if bk == nil {
|
||||
|
|
@ -38,17 +40,25 @@ func (bk *BackupKey) Slice() []byte {
|
|||
|
||||
const BackupIDLength = 16
|
||||
|
||||
type BackupID [BackupIDLength]byte
|
||||
type BackupMetadataKey [C.SignalLOCAL_BACKUP_METADATA_KEY_LEN]byte
|
||||
type BackupMediaID [C.SignalMEDIA_ID_LEN]byte
|
||||
type BackupMediaKey [C.SignalMEDIA_ENCRYPTION_KEY_LEN]byte
|
||||
type BackupID = fixedArray16
|
||||
type BackupMetadataKey = fixedArray32
|
||||
type BackupMediaID = fixedArray15
|
||||
type BackupMediaKey = fixedArray64
|
||||
|
||||
func (bk *BackupKey) cFixedArray() *C.SignalType_FixedArray32_uint8_t {
|
||||
return (*C.SignalType_FixedArray32_uint8_t)(unsafe.Pointer(bk))
|
||||
}
|
||||
|
||||
func (bk *BackupKey) cConstFixedArray() cFixedArray32Compat {
|
||||
return cFixedArray32Compat(bk.cFixedArray())
|
||||
}
|
||||
|
||||
func GenerateRandomBackupKey() *BackupKey {
|
||||
return (*BackupKey)(random.Bytes(C.SignalBACKUP_KEY_LEN))
|
||||
return (*BackupKey)(random.Bytes(BackupKeyLength))
|
||||
}
|
||||
|
||||
func BytesToBackupKey(bytes []byte) *BackupKey {
|
||||
if len(bytes) != C.SignalBACKUP_KEY_LEN {
|
||||
if len(bytes) != BackupKeyLength {
|
||||
return nil
|
||||
}
|
||||
return (*BackupKey)(bytes)
|
||||
|
|
@ -57,9 +67,9 @@ func BytesToBackupKey(bytes []byte) *BackupKey {
|
|||
func (bk *BackupKey) DeriveBackupID(aci ServiceID) (*BackupID, error) {
|
||||
var out BackupID
|
||||
signalFfiError := C.signal_backup_key_derive_backup_id(
|
||||
(*[BackupIDLength]C.uint8_t)(unsafe.Pointer(&out)),
|
||||
(*[C.SignalBACKUP_KEY_LEN]C.uint8_t)(unsafe.Pointer(bk)),
|
||||
aci.CFixedBytes(),
|
||||
out.cFixedArray(),
|
||||
bk.cConstFixedArray(),
|
||||
aci.cConstFixedArray(),
|
||||
)
|
||||
runtime.KeepAlive(bk)
|
||||
if signalFfiError != nil {
|
||||
|
|
@ -72,8 +82,8 @@ func (bk *BackupKey) DeriveECKey(aci ServiceID) (*PrivateKey, error) {
|
|||
var out C.SignalMutPointerPrivateKey
|
||||
signalFfiError := C.signal_backup_key_derive_ec_key(
|
||||
&out,
|
||||
(*[C.SignalBACKUP_KEY_LEN]C.uint8_t)(unsafe.Pointer(&bk)),
|
||||
aci.CFixedBytes(),
|
||||
bk.cConstFixedArray(),
|
||||
aci.cConstFixedArray(),
|
||||
)
|
||||
runtime.KeepAlive(bk)
|
||||
if signalFfiError != nil {
|
||||
|
|
@ -85,8 +95,8 @@ func (bk *BackupKey) DeriveECKey(aci ServiceID) (*PrivateKey, error) {
|
|||
func (bk *BackupKey) DeriveLocalBackupMetadataKey() (*BackupMetadataKey, error) {
|
||||
var out BackupMetadataKey
|
||||
signalFfiError := C.signal_backup_key_derive_local_backup_metadata_key(
|
||||
(*[C.SignalLOCAL_BACKUP_METADATA_KEY_LEN]C.uint8_t)(unsafe.Pointer(&out)),
|
||||
(*[C.SignalBACKUP_KEY_LEN]C.uint8_t)(unsafe.Pointer(bk)),
|
||||
out.cFixedArray(),
|
||||
bk.cConstFixedArray(),
|
||||
)
|
||||
runtime.KeepAlive(bk)
|
||||
if signalFfiError != nil {
|
||||
|
|
@ -100,8 +110,8 @@ func (bk *BackupKey) DeriveMediaID(mediaName string) (*BackupMediaID, error) {
|
|||
mediaNameStr, mediaNameFree := GoStringToCString(mediaName)
|
||||
defer mediaNameFree()
|
||||
signalFfiError := C.signal_backup_key_derive_media_id(
|
||||
(*[C.SignalMEDIA_ID_LEN]C.uint8_t)(unsafe.Pointer(&out)),
|
||||
(*[C.SignalBACKUP_KEY_LEN]C.uint8_t)(unsafe.Pointer(bk)),
|
||||
out.cFixedArray(),
|
||||
bk.cConstFixedArray(),
|
||||
mediaNameStr,
|
||||
)
|
||||
runtime.KeepAlive(bk)
|
||||
|
|
@ -114,9 +124,9 @@ func (bk *BackupKey) DeriveMediaID(mediaName string) (*BackupMediaID, error) {
|
|||
func (bk *BackupKey) DeriveMediaEncryptionKey(mediaID *BackupMediaID) (*BackupMediaKey, error) {
|
||||
var out BackupMediaKey
|
||||
signalFfiError := C.signal_backup_key_derive_media_encryption_key(
|
||||
(*[C.SignalMEDIA_ENCRYPTION_KEY_LEN]C.uint8_t)(unsafe.Pointer(&out)),
|
||||
(*[C.SignalBACKUP_KEY_LEN]C.uint8_t)(unsafe.Pointer(bk)),
|
||||
(*[C.SignalMEDIA_ID_LEN]C.uint8_t)(unsafe.Pointer(mediaID)),
|
||||
out.cFixedArray(),
|
||||
bk.cConstFixedArray(),
|
||||
mediaID.cConstFixedArray(),
|
||||
)
|
||||
runtime.KeepAlive(bk)
|
||||
runtime.KeepAlive(mediaID)
|
||||
|
|
@ -129,9 +139,9 @@ func (bk *BackupKey) DeriveMediaEncryptionKey(mediaID *BackupMediaID) (*BackupMe
|
|||
func (bk *BackupKey) DeriveThumbnailTransitEncryptionKey(mediaID *BackupMediaID) (*BackupMediaKey, error) {
|
||||
var out BackupMediaKey
|
||||
signalFfiError := C.signal_backup_key_derive_thumbnail_transit_encryption_key(
|
||||
(*[C.SignalMEDIA_ENCRYPTION_KEY_LEN]C.uint8_t)(unsafe.Pointer(&out)),
|
||||
(*[C.SignalBACKUP_KEY_LEN]C.uint8_t)(unsafe.Pointer(bk)),
|
||||
(*[C.SignalMEDIA_ID_LEN]C.uint8_t)(unsafe.Pointer(mediaID)),
|
||||
out.cFixedArray(),
|
||||
bk.cConstFixedArray(),
|
||||
mediaID.cConstFixedArray(),
|
||||
)
|
||||
runtime.KeepAlive(bk)
|
||||
runtime.KeepAlive(mediaID)
|
||||
|
|
|
|||
|
|
@ -21,12 +21,14 @@ package libsignalgo
|
|||
*/
|
||||
import "C"
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func BorrowedMutableBuffer(length int) C.SignalBorrowedMutableBuffer {
|
||||
if length <= 0 {
|
||||
return C.SignalBorrowedMutableBuffer{}
|
||||
}
|
||||
data := make([]byte, length)
|
||||
return C.SignalBorrowedMutableBuffer{
|
||||
base: (*C.uchar)(unsafe.Pointer(&data[0])),
|
||||
|
|
@ -48,10 +50,9 @@ func ManyBytesToBuffer[T ~[]byte](datas []T) (C.SignalBorrowedSliceOfBuffers, fu
|
|||
buffers := make([]C.SignalBorrowedBuffer, len(datas))
|
||||
var pinner runtime.Pinner
|
||||
for i, data := range datas {
|
||||
if len(data) == 0 {
|
||||
panic(fmt.Errorf("empty slice passed to ManyBytesToBuffer at index %d", i))
|
||||
if len(data) > 0 {
|
||||
pinner.Pin(&data[0])
|
||||
}
|
||||
pinner.Pin(&data[0])
|
||||
buffers[i] = BytesToBuffer(data)
|
||||
}
|
||||
return C.SignalBorrowedSliceOfBuffers{
|
||||
|
|
|
|||
|
|
@ -4,3 +4,9 @@ package libsignalgo
|
|||
#cgo LDFLAGS: -lsignal_ffi -ldl -lm -lz -lstdc++
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"go.mau.fi/mautrix-signal/pkg/libsignalgo/signalversion"
|
||||
)
|
||||
|
||||
const Version = signalversion.Version
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ func NewCiphertextMessage(plaintext *PlaintextContent) (*CiphertextMessage, erro
|
|||
&ciphertextMessage,
|
||||
plaintext.constPtr(),
|
||||
)
|
||||
runtime.KeepAlive(plaintext)
|
||||
if signalFfiError != nil {
|
||||
return nil, wrapError(signalFfiError)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,19 +18,20 @@ package libsignalgo
|
|||
|
||||
/*
|
||||
#include "./libsignal-ffi.h"
|
||||
#include <stdlib.h>
|
||||
*/
|
||||
import "C"
|
||||
import "unsafe"
|
||||
|
||||
func GoStringToCString(str string) (C.SignalCStringPtr, func()) {
|
||||
cStr := C.CString(str)
|
||||
return cStr, func() {
|
||||
return C.SignalCStringPtr(unsafe.Pointer(cStr)), func() {
|
||||
C.free(unsafe.Pointer(cStr))
|
||||
}
|
||||
}
|
||||
|
||||
func CopyCStringToString(cString C.SignalCStringPtr) (s string) {
|
||||
s = C.GoString(cString)
|
||||
s = C.GoString((*C.char)(unsafe.Pointer(cString)))
|
||||
C.signal_free_string(cString)
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,6 +52,8 @@ func NewFingerprint(iterations, version FingerprintVersion, localIdentifier []by
|
|||
BytesToBuffer(remoteIdentifier),
|
||||
remoteKey.constPtr(),
|
||||
)
|
||||
runtime.KeepAlive(localKey)
|
||||
runtime.KeepAlive(remoteKey)
|
||||
if signalFfiError != nil {
|
||||
return nil, wrapError(signalFfiError)
|
||||
}
|
||||
|
|
|
|||
159
pkg/libsignalgo/fixedarray.go
Normal file
159
pkg/libsignalgo/fixedarray.go
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
// 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 libsignalgo
|
||||
|
||||
/*
|
||||
#include "./libsignal-ffi.h"
|
||||
*/
|
||||
import "C"
|
||||
import "unsafe"
|
||||
|
||||
type fixedArray15 [15]byte
|
||||
type fixedArray16 [16]byte
|
||||
type fixedArray17 [17]byte
|
||||
type fixedArray32 [32]byte
|
||||
type fixedArray64 [64]byte
|
||||
type fixedArray65 [65]byte
|
||||
type fixedArray97 [97]byte
|
||||
type fixedArray129 [129]byte
|
||||
type fixedArray153 [153]byte
|
||||
type fixedArray177 [177]byte
|
||||
type fixedArray289 [289]byte
|
||||
type fixedArray329 [329]byte
|
||||
type fixedArray409 [409]byte
|
||||
type fixedArray473 [473]byte
|
||||
type fixedArray497 [497]byte
|
||||
|
||||
func (a *fixedArray15) cFixedArray() *C.SignalType_FixedArray15_uint8_t {
|
||||
return (*C.SignalType_FixedArray15_uint8_t)(unsafe.Pointer(a))
|
||||
}
|
||||
|
||||
func (a *fixedArray15) cConstFixedArray() cFixedArray15Compat {
|
||||
return cFixedArray15Compat(a.cFixedArray())
|
||||
}
|
||||
|
||||
func (a *fixedArray16) cFixedArray() *C.SignalType_FixedArray16_uint8_t {
|
||||
return (*C.SignalType_FixedArray16_uint8_t)(unsafe.Pointer(a))
|
||||
}
|
||||
|
||||
func (a *fixedArray16) cConstFixedArray() cFixedArray16Compat {
|
||||
return cFixedArray16Compat(a.cFixedArray())
|
||||
}
|
||||
|
||||
func (a *fixedArray17) cFixedArray() *C.SignalType_FixedArray17_uint8_t {
|
||||
return (*C.SignalType_FixedArray17_uint8_t)(unsafe.Pointer(a))
|
||||
}
|
||||
|
||||
func (a *fixedArray17) cConstFixedArray() cFixedArray17Compat {
|
||||
return cFixedArray17Compat(a.cFixedArray())
|
||||
}
|
||||
|
||||
func (a *fixedArray32) cFixedArray() *C.SignalType_FixedArray32_uint8_t {
|
||||
return (*C.SignalType_FixedArray32_uint8_t)(unsafe.Pointer(a))
|
||||
}
|
||||
|
||||
func (a *fixedArray32) cConstFixedArray() cFixedArray32Compat {
|
||||
return cFixedArray32Compat(a.cFixedArray())
|
||||
}
|
||||
|
||||
func (a *fixedArray64) cFixedArray() *C.SignalType_FixedArray64_uint8_t {
|
||||
return (*C.SignalType_FixedArray64_uint8_t)(unsafe.Pointer(a))
|
||||
}
|
||||
|
||||
func (a *fixedArray64) cConstFixedArray() cFixedArray64Compat {
|
||||
return cFixedArray64Compat(a.cFixedArray())
|
||||
}
|
||||
|
||||
func (a *fixedArray65) cFixedArray() *C.SignalType_FixedArray65_uint8_t {
|
||||
return (*C.SignalType_FixedArray65_uint8_t)(unsafe.Pointer(a))
|
||||
}
|
||||
|
||||
func (a *fixedArray65) cConstFixedArray() cFixedArray65Compat {
|
||||
return cFixedArray65Compat(a.cFixedArray())
|
||||
}
|
||||
|
||||
func (a *fixedArray97) cFixedArray() *C.SignalType_FixedArray97_uint8_t {
|
||||
return (*C.SignalType_FixedArray97_uint8_t)(unsafe.Pointer(a))
|
||||
}
|
||||
|
||||
func (a *fixedArray97) cConstFixedArray() cFixedArray97Compat {
|
||||
return cFixedArray97Compat(a.cFixedArray())
|
||||
}
|
||||
|
||||
func (a *fixedArray129) cFixedArray() *C.SignalType_FixedArray129_uint8_t {
|
||||
return (*C.SignalType_FixedArray129_uint8_t)(unsafe.Pointer(a))
|
||||
}
|
||||
|
||||
func (a *fixedArray129) cConstFixedArray() cFixedArray129Compat {
|
||||
return cFixedArray129Compat(a.cFixedArray())
|
||||
}
|
||||
|
||||
func (a *fixedArray153) cFixedArray() *C.SignalType_FixedArray153_uint8_t {
|
||||
return (*C.SignalType_FixedArray153_uint8_t)(unsafe.Pointer(a))
|
||||
}
|
||||
|
||||
func (a *fixedArray153) cConstFixedArray() cFixedArray153Compat {
|
||||
return cFixedArray153Compat(a.cFixedArray())
|
||||
}
|
||||
|
||||
func (a *fixedArray177) cFixedArray() *C.SignalType_FixedArray177_uint8_t {
|
||||
return (*C.SignalType_FixedArray177_uint8_t)(unsafe.Pointer(a))
|
||||
}
|
||||
|
||||
func (a *fixedArray177) cConstFixedArray() cFixedArray177Compat {
|
||||
return cFixedArray177Compat(a.cFixedArray())
|
||||
}
|
||||
|
||||
func (a *fixedArray289) cFixedArray() *C.SignalType_FixedArray289_uint8_t {
|
||||
return (*C.SignalType_FixedArray289_uint8_t)(unsafe.Pointer(a))
|
||||
}
|
||||
|
||||
func (a *fixedArray289) cConstFixedArray() cFixedArray289Compat {
|
||||
return cFixedArray289Compat(a.cFixedArray())
|
||||
}
|
||||
|
||||
func (a *fixedArray329) cFixedArray() *C.SignalType_FixedArray329_uint8_t {
|
||||
return (*C.SignalType_FixedArray329_uint8_t)(unsafe.Pointer(a))
|
||||
}
|
||||
|
||||
func (a *fixedArray329) cConstFixedArray() cFixedArray329Compat {
|
||||
return cFixedArray329Compat(a.cFixedArray())
|
||||
}
|
||||
|
||||
func (a *fixedArray409) cFixedArray() *C.SignalType_FixedArray409_uint8_t {
|
||||
return (*C.SignalType_FixedArray409_uint8_t)(unsafe.Pointer(a))
|
||||
}
|
||||
|
||||
func (a *fixedArray409) cConstFixedArray() cFixedArray409Compat {
|
||||
return cFixedArray409Compat(a.cFixedArray())
|
||||
}
|
||||
|
||||
func (a *fixedArray473) cFixedArray() *C.SignalType_FixedArray473_uint8_t {
|
||||
return (*C.SignalType_FixedArray473_uint8_t)(unsafe.Pointer(a))
|
||||
}
|
||||
|
||||
func (a *fixedArray473) cConstFixedArray() cFixedArray473Compat {
|
||||
return cFixedArray473Compat(a.cFixedArray())
|
||||
}
|
||||
|
||||
func (a *fixedArray497) cFixedArray() *C.SignalType_FixedArray497_uint8_t {
|
||||
return (*C.SignalType_FixedArray497_uint8_t)(unsafe.Pointer(a))
|
||||
}
|
||||
|
||||
func (a *fixedArray497) cConstFixedArray() cFixedArray497Compat {
|
||||
return cFixedArray497Compat(a.cFixedArray())
|
||||
}
|
||||
24
pkg/libsignalgo/fixedarray_clang.go
Normal file
24
pkg/libsignalgo/fixedarray_clang.go
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
//go:build darwin || android || ios || (windows && arm64)
|
||||
|
||||
package libsignalgo
|
||||
|
||||
/*
|
||||
#include "./libsignal-ffi.h"
|
||||
*/
|
||||
import "C"
|
||||
|
||||
type cFixedArray15Compat = *C.SignalType_FixedArray15_uint8_t
|
||||
type cFixedArray16Compat = *C.SignalType_FixedArray16_uint8_t
|
||||
type cFixedArray17Compat = *C.SignalType_FixedArray17_uint8_t
|
||||
type cFixedArray32Compat = *C.SignalType_FixedArray32_uint8_t
|
||||
type cFixedArray64Compat = *C.SignalType_FixedArray64_uint8_t
|
||||
type cFixedArray65Compat = *C.SignalType_FixedArray65_uint8_t
|
||||
type cFixedArray97Compat = *C.SignalType_FixedArray97_uint8_t
|
||||
type cFixedArray129Compat = *C.SignalType_FixedArray129_uint8_t
|
||||
type cFixedArray153Compat = *C.SignalType_FixedArray153_uint8_t
|
||||
type cFixedArray177Compat = *C.SignalType_FixedArray177_uint8_t
|
||||
type cFixedArray289Compat = *C.SignalType_FixedArray289_uint8_t
|
||||
type cFixedArray329Compat = *C.SignalType_FixedArray329_uint8_t
|
||||
type cFixedArray409Compat = *C.SignalType_FixedArray409_uint8_t
|
||||
type cFixedArray473Compat = *C.SignalType_FixedArray473_uint8_t
|
||||
type cFixedArray497Compat = *C.SignalType_FixedArray497_uint8_t
|
||||
26
pkg/libsignalgo/fixedarray_gcc.go
Normal file
26
pkg/libsignalgo/fixedarray_gcc.go
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
//go:build !(darwin || android || ios || (windows && arm64))
|
||||
|
||||
package libsignalgo
|
||||
|
||||
/*
|
||||
#include "./libsignal-ffi.h"
|
||||
*/
|
||||
import "C"
|
||||
|
||||
// Hack for https://github.com/golang/go/issues/7270
|
||||
// The clang version is more correct, but doesn't work with gcc.
|
||||
type cFixedArray15Compat = *[15]C.uint8_t
|
||||
type cFixedArray16Compat = *[16]C.uint8_t
|
||||
type cFixedArray17Compat = *[17]C.uint8_t
|
||||
type cFixedArray32Compat = *[32]C.uint8_t
|
||||
type cFixedArray64Compat = *[64]C.uint8_t
|
||||
type cFixedArray65Compat = *[65]C.uint8_t
|
||||
type cFixedArray97Compat = *[97]C.uint8_t
|
||||
type cFixedArray129Compat = *[129]C.uint8_t
|
||||
type cFixedArray153Compat = *[153]C.uint8_t
|
||||
type cFixedArray177Compat = *[177]C.uint8_t
|
||||
type cFixedArray289Compat = *[289]C.uint8_t
|
||||
type cFixedArray329Compat = *[329]C.uint8_t
|
||||
type cFixedArray409Compat = *[409]C.uint8_t
|
||||
type cFixedArray473Compat = *[473]C.uint8_t
|
||||
type cFixedArray497Compat = *[497]C.uint8_t
|
||||
|
|
@ -31,7 +31,9 @@ import (
|
|||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type Randomness [C.SignalRANDOMNESS_LEN]byte
|
||||
const RandomnessLength = 32
|
||||
|
||||
type Randomness = fixedArray32
|
||||
|
||||
func GenerateRandomness() Randomness {
|
||||
var randomness Randomness
|
||||
|
|
@ -42,14 +44,39 @@ func GenerateRandomness() Randomness {
|
|||
return randomness
|
||||
}
|
||||
|
||||
const GroupMasterKeyLength = C.SignalGROUP_MASTER_KEY_LEN
|
||||
const GroupIdentifierLength = C.SignalGROUP_IDENTIFIER_LEN
|
||||
const GroupMasterKeyLength = 32
|
||||
const GroupIdentifierLength = 32
|
||||
const GroupSecretParamsLength = 289
|
||||
|
||||
type GroupMasterKey [GroupMasterKeyLength]byte
|
||||
type GroupSecretParams [C.SignalGROUP_SECRET_PARAMS_LEN]byte
|
||||
type GroupPublicParams [C.SignalGROUP_PUBLIC_PARAMS_LEN]byte
|
||||
type GroupSecretParams [GroupSecretParamsLength]byte
|
||||
type GroupPublicParams = fixedArray97
|
||||
type GroupIdentifier [GroupIdentifierLength]byte
|
||||
|
||||
func (gmk *GroupMasterKey) cFixedArray() *C.SignalType_FixedArray32_uint8_t {
|
||||
return (*C.SignalType_FixedArray32_uint8_t)(unsafe.Pointer(gmk))
|
||||
}
|
||||
|
||||
func (gmk *GroupMasterKey) cConstFixedArray() cFixedArray32Compat {
|
||||
return cFixedArray32Compat(gmk.cFixedArray())
|
||||
}
|
||||
|
||||
func (gsp *GroupSecretParams) cFixedArray() *C.SignalType_FixedArray289_uint8_t {
|
||||
return (*C.SignalType_FixedArray289_uint8_t)(unsafe.Pointer(gsp))
|
||||
}
|
||||
|
||||
func (gsp *GroupSecretParams) cConstFixedArray() cFixedArray289Compat {
|
||||
return cFixedArray289Compat(gsp.cFixedArray())
|
||||
}
|
||||
|
||||
func (gid *GroupIdentifier) cFixedArray() *C.SignalType_FixedArray32_uint8_t {
|
||||
return (*C.SignalType_FixedArray32_uint8_t)(unsafe.Pointer(gid))
|
||||
}
|
||||
|
||||
func (gid *GroupIdentifier) cConstFixedArray() cFixedArray32Compat {
|
||||
return cFixedArray32Compat(gid.cFixedArray())
|
||||
}
|
||||
|
||||
func (gid *GroupIdentifier) String() string {
|
||||
if gid == nil {
|
||||
return ""
|
||||
|
|
@ -57,8 +84,8 @@ func (gid *GroupIdentifier) String() string {
|
|||
return base64.StdEncoding.EncodeToString(gid[:])
|
||||
}
|
||||
|
||||
type UUIDCiphertext [C.SignalUUID_CIPHERTEXT_LEN]byte
|
||||
type ProfileKeyCiphertext [C.SignalPROFILE_KEY_CIPHERTEXT_LEN]byte
|
||||
type UUIDCiphertext = fixedArray65
|
||||
type ProfileKeyCiphertext = fixedArray65
|
||||
|
||||
func GenerateGroupSecretParams() (GroupSecretParams, error) {
|
||||
return GenerateGroupSecretParamsWithRandomness(GenerateRandomness())
|
||||
|
|
@ -81,51 +108,43 @@ func (gmk GroupMasterKey) SecretParams() (GroupSecretParams, error) {
|
|||
}
|
||||
|
||||
func GenerateGroupSecretParamsWithRandomness(randomness Randomness) (GroupSecretParams, error) {
|
||||
var params [C.SignalGROUP_SECRET_PARAMS_LEN]C.uchar
|
||||
signalFfiError := C.signal_group_secret_params_generate_deterministic(¶ms, (*[C.SignalRANDOMNESS_LEN]C.uint8_t)(unsafe.Pointer(&randomness)))
|
||||
var params GroupSecretParams
|
||||
signalFfiError := C.signal_group_secret_params_generate_deterministic(params.cFixedArray(), randomness.cConstFixedArray())
|
||||
runtime.KeepAlive(randomness)
|
||||
if signalFfiError != nil {
|
||||
return GroupSecretParams{}, wrapError(signalFfiError)
|
||||
}
|
||||
var groupSecretParams GroupSecretParams
|
||||
copy(groupSecretParams[:], C.GoBytes(unsafe.Pointer(¶ms), C.int(C.SignalGROUP_SECRET_PARAMS_LEN)))
|
||||
return groupSecretParams, nil
|
||||
return params, nil
|
||||
}
|
||||
|
||||
func DeriveGroupSecretParamsFromMasterKey(groupMasterKey GroupMasterKey) (GroupSecretParams, error) {
|
||||
var params [C.SignalGROUP_SECRET_PARAMS_LEN]C.uchar
|
||||
signalFfiError := C.signal_group_secret_params_derive_from_master_key(¶ms, (*[C.SignalGROUP_MASTER_KEY_LEN]C.uint8_t)(unsafe.Pointer(&groupMasterKey)))
|
||||
var params GroupSecretParams
|
||||
signalFfiError := C.signal_group_secret_params_derive_from_master_key(params.cFixedArray(), groupMasterKey.cConstFixedArray())
|
||||
runtime.KeepAlive(groupMasterKey)
|
||||
if signalFfiError != nil {
|
||||
return GroupSecretParams{}, wrapError(signalFfiError)
|
||||
}
|
||||
var groupSecretParams GroupSecretParams
|
||||
copy(groupSecretParams[:], C.GoBytes(unsafe.Pointer(¶ms), C.int(C.SignalGROUP_SECRET_PARAMS_LEN)))
|
||||
return groupSecretParams, nil
|
||||
return params, nil
|
||||
}
|
||||
|
||||
func (gsp *GroupSecretParams) GetPublicParams() (*GroupPublicParams, error) {
|
||||
var publicParams [C.SignalGROUP_PUBLIC_PARAMS_LEN]C.uchar
|
||||
signalFfiError := C.signal_group_secret_params_get_public_params(&publicParams, (*[C.SignalGROUP_SECRET_PARAMS_LEN]C.uint8_t)(unsafe.Pointer(gsp)))
|
||||
var publicParams GroupPublicParams
|
||||
signalFfiError := C.signal_group_secret_params_get_public_params(publicParams.cFixedArray(), gsp.cConstFixedArray())
|
||||
runtime.KeepAlive(gsp)
|
||||
if signalFfiError != nil {
|
||||
return nil, wrapError(signalFfiError)
|
||||
}
|
||||
var groupPublicParams GroupPublicParams
|
||||
copy(groupPublicParams[:], C.GoBytes(unsafe.Pointer(&publicParams), C.int(C.SignalGROUP_PUBLIC_PARAMS_LEN)))
|
||||
return &groupPublicParams, nil
|
||||
return &publicParams, nil
|
||||
}
|
||||
|
||||
func GetGroupIdentifier(groupPublicParams GroupPublicParams) (*GroupIdentifier, error) {
|
||||
var groupIdentifier [C.SignalGROUP_IDENTIFIER_LEN]C.uchar
|
||||
signalFfiError := C.signal_group_public_params_get_group_identifier(&groupIdentifier, (*[C.SignalGROUP_PUBLIC_PARAMS_LEN]C.uint8_t)(unsafe.Pointer(&groupPublicParams)))
|
||||
var groupIdentifier GroupIdentifier
|
||||
signalFfiError := C.signal_group_public_params_get_group_identifier(groupIdentifier.cFixedArray(), groupPublicParams.cConstFixedArray())
|
||||
runtime.KeepAlive(groupPublicParams)
|
||||
if signalFfiError != nil {
|
||||
return nil, wrapError(signalFfiError)
|
||||
}
|
||||
var result GroupIdentifier
|
||||
copy(result[:], C.GoBytes(unsafe.Pointer(&groupIdentifier), C.int(C.SignalGROUP_IDENTIFIER_LEN)))
|
||||
return &result, nil
|
||||
return &groupIdentifier, nil
|
||||
}
|
||||
|
||||
func (gsp *GroupSecretParams) DecryptBlobWithPadding(blob []byte) ([]byte, error) {
|
||||
|
|
@ -133,7 +152,7 @@ func (gsp *GroupSecretParams) DecryptBlobWithPadding(blob []byte) ([]byte, error
|
|||
borrowedBlob := BytesToBuffer(blob)
|
||||
signalFfiError := C.signal_group_secret_params_decrypt_blob_with_padding(
|
||||
&plaintext,
|
||||
(*[C.SignalGROUP_SECRET_PARAMS_LEN]C.uint8_t)(unsafe.Pointer(gsp)),
|
||||
gsp.cConstFixedArray(),
|
||||
borrowedBlob,
|
||||
)
|
||||
runtime.KeepAlive(gsp)
|
||||
|
|
@ -149,8 +168,8 @@ func (gsp *GroupSecretParams) EncryptBlobWithPaddingDeterministic(randomness Ran
|
|||
borrowedPlaintext := BytesToBuffer(plaintext)
|
||||
signalFfiError := C.signal_group_secret_params_encrypt_blob_with_padding_deterministic(
|
||||
&ciphertext,
|
||||
(*[C.SignalGROUP_SECRET_PARAMS_LEN]C.uint8_t)(unsafe.Pointer(gsp)),
|
||||
(*[C.SignalRANDOMNESS_LEN]C.uint8_t)(unsafe.Pointer(&randomness)),
|
||||
gsp.cConstFixedArray(),
|
||||
randomness.cConstFixedArray(),
|
||||
borrowedPlaintext,
|
||||
(C.uint32_t)(padding_len),
|
||||
)
|
||||
|
|
@ -165,11 +184,11 @@ func (gsp *GroupSecretParams) EncryptBlobWithPaddingDeterministic(randomness Ran
|
|||
}
|
||||
|
||||
func (gsp *GroupSecretParams) DecryptServiceID(ciphertextServiceID UUIDCiphertext) (ServiceID, error) {
|
||||
u := C.SignalServiceIdFixedWidthBinaryBytes{}
|
||||
var serviceIDBytes ServiceIDFixedBytes
|
||||
signalFfiError := C.signal_group_secret_params_decrypt_service_id(
|
||||
&u,
|
||||
(*[C.SignalGROUP_SECRET_PARAMS_LEN]C.uint8_t)(unsafe.Pointer(gsp)),
|
||||
(*[C.SignalUUID_CIPHERTEXT_LEN]C.uint8_t)(unsafe.Pointer(&ciphertextServiceID)),
|
||||
serviceIDBytes.cFixedArray(),
|
||||
gsp.cConstFixedArray(),
|
||||
ciphertextServiceID.cConstFixedArray(),
|
||||
)
|
||||
runtime.KeepAlive(gsp)
|
||||
runtime.KeepAlive(ciphertextServiceID)
|
||||
|
|
@ -177,33 +196,31 @@ func (gsp *GroupSecretParams) DecryptServiceID(ciphertextServiceID UUIDCiphertex
|
|||
return EmptyServiceID, wrapError(signalFfiError)
|
||||
}
|
||||
|
||||
serviceID := ServiceIDFromCFixedBytes(&u)
|
||||
serviceID := ServiceIDFromCFixedBytes(serviceIDBytes.cFixedArray())
|
||||
return serviceID, nil
|
||||
}
|
||||
|
||||
func (gsp *GroupSecretParams) EncryptServiceID(serviceID ServiceID) (*UUIDCiphertext, error) {
|
||||
var cipherTextServiceID [C.SignalUUID_CIPHERTEXT_LEN]C.uchar
|
||||
var cipherTextServiceID UUIDCiphertext
|
||||
signalFfiError := C.signal_group_secret_params_encrypt_service_id(
|
||||
&cipherTextServiceID,
|
||||
(*[C.SignalGROUP_SECRET_PARAMS_LEN]C.uint8_t)(unsafe.Pointer(gsp)),
|
||||
serviceID.CFixedBytes(),
|
||||
cipherTextServiceID.cFixedArray(),
|
||||
gsp.cConstFixedArray(),
|
||||
serviceID.cConstFixedArray(),
|
||||
)
|
||||
runtime.KeepAlive(gsp)
|
||||
if signalFfiError != nil {
|
||||
return nil, wrapError(signalFfiError)
|
||||
}
|
||||
var result UUIDCiphertext
|
||||
copy(result[:], C.GoBytes(unsafe.Pointer(&cipherTextServiceID), C.int(C.SignalUUID_CIPHERTEXT_LEN)))
|
||||
return &result, nil
|
||||
return &cipherTextServiceID, nil
|
||||
}
|
||||
|
||||
func (gsp *GroupSecretParams) DecryptProfileKey(ciphertextProfileKey ProfileKeyCiphertext, u uuid.UUID) (*ProfileKey, error) {
|
||||
profileKey := [C.SignalPROFILE_KEY_LEN]C.uchar{}
|
||||
var profileKey ProfileKey
|
||||
signalFfiError := C.signal_group_secret_params_decrypt_profile_key(
|
||||
&profileKey,
|
||||
(*[C.SignalGROUP_SECRET_PARAMS_LEN]C.uint8_t)(unsafe.Pointer(gsp)),
|
||||
(*[C.SignalPROFILE_KEY_CIPHERTEXT_LEN]C.uint8_t)(unsafe.Pointer(&ciphertextProfileKey)),
|
||||
NewACIServiceID(u).CFixedBytes(),
|
||||
profileKey.cFixedArray(),
|
||||
gsp.cConstFixedArray(),
|
||||
ciphertextProfileKey.cConstFixedArray(),
|
||||
NewACIServiceID(u).cConstFixedArray(),
|
||||
)
|
||||
runtime.KeepAlive(gsp)
|
||||
runtime.KeepAlive(ciphertextProfileKey)
|
||||
|
|
@ -211,27 +228,23 @@ func (gsp *GroupSecretParams) DecryptProfileKey(ciphertextProfileKey ProfileKeyC
|
|||
if signalFfiError != nil {
|
||||
return nil, wrapError(signalFfiError)
|
||||
}
|
||||
var result ProfileKey
|
||||
copy(result[:], C.GoBytes(unsafe.Pointer(&profileKey), C.int(C.SignalPROFILE_KEY_LEN)))
|
||||
return &result, nil
|
||||
return &profileKey, nil
|
||||
}
|
||||
|
||||
func (gsp *GroupSecretParams) EncryptProfileKey(profileKey ProfileKey, u uuid.UUID) (*ProfileKeyCiphertext, error) {
|
||||
ciphertextProfileKey := [C.SignalPROFILE_KEY_CIPHERTEXT_LEN]C.uchar{}
|
||||
var ciphertextProfileKey ProfileKeyCiphertext
|
||||
signalFfiError := C.signal_group_secret_params_encrypt_profile_key(
|
||||
&ciphertextProfileKey,
|
||||
(*[C.SignalGROUP_SECRET_PARAMS_LEN]C.uint8_t)(unsafe.Pointer(gsp)),
|
||||
(*[C.SignalPROFILE_KEY_LEN]C.uint8_t)(unsafe.Pointer(&profileKey)),
|
||||
NewACIServiceID(u).CFixedBytes(),
|
||||
ciphertextProfileKey.cFixedArray(),
|
||||
gsp.cConstFixedArray(),
|
||||
profileKey.cConstFixedArray(),
|
||||
NewACIServiceID(u).cConstFixedArray(),
|
||||
)
|
||||
runtime.KeepAlive(gsp)
|
||||
runtime.KeepAlive(profileKey)
|
||||
if signalFfiError != nil {
|
||||
return nil, wrapError(signalFfiError)
|
||||
}
|
||||
var result ProfileKeyCiphertext
|
||||
copy(result[:], C.GoBytes(unsafe.Pointer(&ciphertextProfileKey), C.int(C.SignalPROFILE_KEY_CIPHERTEXT_LEN)))
|
||||
return &result, nil
|
||||
return &ciphertextProfileKey, nil
|
||||
}
|
||||
|
||||
func (gsp *GroupSecretParams) CreateExpiringProfileKeyCredentialPresentation(spp *ServerPublicParams, credential ExpiringProfileKeyCredential) (*ProfileKeyCredentialPresentation, error) {
|
||||
|
|
@ -240,9 +253,9 @@ func (gsp *GroupSecretParams) CreateExpiringProfileKeyCredentialPresentation(spp
|
|||
signalFfiError := C.signal_server_public_params_create_expiring_profile_key_credential_presentation_deterministic(
|
||||
&out,
|
||||
C.SignalConstPointerServerPublicParams{spp},
|
||||
(*[C.SignalRANDOMNESS_LEN]C.uint8_t)(unsafe.Pointer(&randomness)),
|
||||
(*[C.SignalGROUP_SECRET_PARAMS_LEN]C.uchar)(unsafe.Pointer(gsp)),
|
||||
(*[C.SignalEXPIRING_PROFILE_KEY_CREDENTIAL_LEN]C.uchar)(unsafe.Pointer(&credential)),
|
||||
randomness.cConstFixedArray(),
|
||||
gsp.cConstFixedArray(),
|
||||
credential.cConstFixedArray(),
|
||||
)
|
||||
runtime.KeepAlive(gsp)
|
||||
runtime.KeepAlive(credential)
|
||||
|
|
@ -256,16 +269,14 @@ func (gsp *GroupSecretParams) CreateExpiringProfileKeyCredentialPresentation(spp
|
|||
}
|
||||
|
||||
func (gsp *GroupSecretParams) GetMasterKey() (*GroupMasterKey, error) {
|
||||
masterKeyBytes := [C.SignalGROUP_MASTER_KEY_LEN]C.uchar{}
|
||||
var masterKey GroupMasterKey
|
||||
signalFfiError := C.signal_group_secret_params_get_master_key(
|
||||
&masterKeyBytes,
|
||||
(*[C.SignalGROUP_SECRET_PARAMS_LEN]C.uchar)(unsafe.Pointer(gsp)),
|
||||
masterKey.cFixedArray(),
|
||||
gsp.cConstFixedArray(),
|
||||
)
|
||||
runtime.KeepAlive(gsp)
|
||||
if signalFfiError != nil {
|
||||
return nil, wrapError(signalFfiError)
|
||||
}
|
||||
var groupMasterKey GroupMasterKey
|
||||
copy(groupMasterKey[:], C.GoBytes(unsafe.Pointer(&masterKeyBytes), C.int(C.SignalGROUP_MASTER_KEY_LEN)))
|
||||
return &groupMasterKey, nil
|
||||
return &masterKey, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ import (
|
|||
"encoding/base64"
|
||||
"runtime"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type GroupSendFullToken []byte
|
||||
|
|
@ -91,7 +90,7 @@ func (gse GroupSendEndorsement) ToToken(groupSecretParams *GroupSecretParams) (G
|
|||
signalFfiError := C.signal_group_send_endorsement_to_token(
|
||||
&token,
|
||||
BytesToBuffer(gse),
|
||||
(*[C.SignalGROUP_SECRET_PARAMS_LEN]C.uint8_t)(unsafe.Pointer(groupSecretParams)),
|
||||
groupSecretParams.cConstFixedArray(),
|
||||
)
|
||||
runtime.KeepAlive(gse)
|
||||
runtime.KeepAlive(groupSecretParams)
|
||||
|
|
@ -180,17 +179,17 @@ func (gser GroupSendEndorsementsResponse) ReceiveWithServiceIDs(
|
|||
groupMembers []ServiceID, localUser ServiceID, params *GroupSecretParams, spp *ServerPublicParams,
|
||||
) (GroupSendEndorsement, map[ServiceID]GroupSendEndorsement, error) {
|
||||
var out C.SignalBytestringArray = C.SignalBytestringArray{}
|
||||
concatenatedMembers := make([]byte, len(groupMembers)*17)
|
||||
concatenatedMembers := make([]byte, len(groupMembers)*ServiceIDFixedBytesLength)
|
||||
for i, member := range groupMembers {
|
||||
copy(concatenatedMembers[i*17:(i+1)*17], member.FixedBytes()[:])
|
||||
copy(concatenatedMembers[i*ServiceIDFixedBytesLength:(i+1)*ServiceIDFixedBytesLength], member.FixedBytes()[:])
|
||||
}
|
||||
signalFfiError := C.signal_group_send_endorsements_response_receive_and_combine_with_service_ids(
|
||||
&out,
|
||||
BytesToBuffer(gser),
|
||||
BytesToBuffer(concatenatedMembers),
|
||||
localUser.CFixedBytes(),
|
||||
localUser.cConstFixedArray(),
|
||||
C.uint64_t(time.Now().Unix()),
|
||||
(*[C.SignalGROUP_SECRET_PARAMS_LEN]C.uint8_t)(unsafe.Pointer(params)),
|
||||
params.cConstFixedArray(),
|
||||
C.SignalConstPointerServerPublicParams{spp},
|
||||
)
|
||||
runtime.KeepAlive(gser)
|
||||
|
|
@ -207,7 +206,13 @@ func (gser GroupSendEndorsementsResponse) ReceiveWithServiceIDs(
|
|||
memberEndorsements[member] = endorsements[i]
|
||||
}
|
||||
}
|
||||
combined, err := GroupSendEndorsementCombine(endorsements...)
|
||||
nonEmptyEndorsements := make([]GroupSendEndorsement, 0, len(endorsements))
|
||||
for _, endorsement := range endorsements {
|
||||
if len(endorsement) > 0 {
|
||||
nonEmptyEndorsements = append(nonEmptyEndorsements, endorsement)
|
||||
}
|
||||
}
|
||||
combined, err := GroupSendEndorsementCombine(nonEmptyEndorsements...)
|
||||
if err != nil {
|
||||
return nil, memberEndorsements, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 4e9bd5d7feca2f61cf2ce0c7d99a60eb8b9e0102
|
||||
Subproject commit 8fc2113bda042fc972a166a24b974b0d34155c6c
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -19,8 +19,8 @@ package libsignalgo
|
|||
/*
|
||||
#include <./libsignal-ffi.h>
|
||||
|
||||
extern void signal_log_callback(void *ctx, SignalLogLevel level, SignalCStringPtr file, uint32_t line, SignalCStringPtr message);
|
||||
extern void signal_log_flush_callback(void *ctx);
|
||||
extern int signal_log_callback(void *ctx, SignalLogLevel level, SignalCStringPtr file, uint32_t line, SignalCStringPtr message);
|
||||
extern int signal_log_flush_callback(void *ctx);
|
||||
extern void signal_log_destroy_callback(void *ctx);
|
||||
*/
|
||||
import "C"
|
||||
|
|
@ -32,13 +32,15 @@ import (
|
|||
var ffiLogger Logger
|
||||
|
||||
//export signal_log_callback
|
||||
func signal_log_callback(ctx unsafe.Pointer, level C.SignalLogLevel, file C.SignalCStringPtr, line C.uint32_t, message C.SignalCStringPtr) {
|
||||
ffiLogger.Log(LogLevel(int(level)), C.GoString(file), uint(line), C.GoString(message))
|
||||
func signal_log_callback(ctx unsafe.Pointer, level C.SignalLogLevel, file C.SignalCStringPtr, line C.uint32_t, message C.SignalCStringPtr) C.int {
|
||||
ffiLogger.Log(LogLevel(int(level)), CopyCStringToString(file), uint(line), CopyCStringToString(message))
|
||||
return 0
|
||||
}
|
||||
|
||||
//export signal_log_flush_callback
|
||||
func signal_log_flush_callback(ctx unsafe.Pointer) {
|
||||
func signal_log_flush_callback(ctx unsafe.Pointer) C.int {
|
||||
ffiLogger.Flush()
|
||||
return 0
|
||||
}
|
||||
|
||||
//export signal_log_destroy_callback
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ func Encrypt(ctx context.Context, plaintext []byte, forAddress, localAddress *Ad
|
|||
)
|
||||
runtime.KeepAlive(plaintext)
|
||||
runtime.KeepAlive(forAddress)
|
||||
runtime.KeepAlive(localAddress)
|
||||
if signalFfiError != nil {
|
||||
return nil, callbackCtx.wrapError(signalFfiError)
|
||||
}
|
||||
|
|
@ -63,6 +64,7 @@ func Decrypt(ctx context.Context, message *Message, fromAddress, localAddress *A
|
|||
)
|
||||
runtime.KeepAlive(message)
|
||||
runtime.KeepAlive(fromAddress)
|
||||
runtime.KeepAlive(localAddress)
|
||||
if signalFfiError != nil {
|
||||
return nil, callbackCtx.wrapError(signalFfiError)
|
||||
}
|
||||
|
|
@ -71,10 +73,10 @@ func Decrypt(ctx context.Context, message *Message, fromAddress, localAddress *A
|
|||
|
||||
type Message struct {
|
||||
nc noCopy
|
||||
ptr *C.SignalMessage
|
||||
ptr *C.SignalSignalMessage
|
||||
}
|
||||
|
||||
func wrapMessage(ptr *C.SignalMessage) *Message {
|
||||
func wrapMessage(ptr *C.SignalSignalMessage) *Message {
|
||||
message := &Message{ptr: ptr}
|
||||
runtime.SetFinalizer(message, (*Message).Destroy)
|
||||
return message
|
||||
|
|
|
|||
|
|
@ -20,16 +20,17 @@ package libsignalgo
|
|||
#include "./libsignal-ffi.h"
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"runtime"
|
||||
"unsafe"
|
||||
)
|
||||
import "runtime"
|
||||
|
||||
type MessageBackupKey struct {
|
||||
nc noCopy
|
||||
ptr *C.SignalMessageBackupKey
|
||||
}
|
||||
|
||||
const MessageBackupKeyBytesLength = 32
|
||||
|
||||
type messageBackupKeyBytes = fixedArray32
|
||||
|
||||
func wrapMessageBackupKey(ptr *C.SignalMessageBackupKey) *MessageBackupKey {
|
||||
backupKey := &MessageBackupKey{ptr: ptr}
|
||||
runtime.SetFinalizer(backupKey, (*MessageBackupKey).Destroy)
|
||||
|
|
@ -43,7 +44,7 @@ func MessageBackupKeyFromAccountEntropyPool(aep AccountEntropyPool, aci ServiceI
|
|||
signalFfiError := C.signal_message_backup_key_from_account_entropy_pool(
|
||||
&bk,
|
||||
aepC,
|
||||
aci.CFixedBytes(),
|
||||
aci.cConstFixedArray(),
|
||||
nil, // TODO what's a forward secrecy token?
|
||||
)
|
||||
runtime.KeepAlive(aep)
|
||||
|
|
@ -57,8 +58,8 @@ func MessageBackupKeyFromBackupKeyAndID(backupKey *BackupKey, backupID *BackupID
|
|||
var bk C.SignalMutPointerMessageBackupKey
|
||||
signalFfiError := C.signal_message_backup_key_from_backup_key_and_backup_id(
|
||||
&bk,
|
||||
(*[C.SignalBACKUP_KEY_LEN]C.uint8_t)(unsafe.Pointer(backupKey)),
|
||||
(*[BackupIDLength]C.uint8_t)(unsafe.Pointer(backupID)),
|
||||
backupKey.cConstFixedArray(),
|
||||
backupID.cConstFixedArray(),
|
||||
nil, // TODO what's a forward secrecy token?
|
||||
)
|
||||
runtime.KeepAlive(backupKey)
|
||||
|
|
@ -82,26 +83,28 @@ func (bk *MessageBackupKey) Destroy() error {
|
|||
return wrapError(C.signal_message_backup_key_destroy(bk.mutPtr()))
|
||||
}
|
||||
|
||||
func (bk *MessageBackupKey) GetHMACKey() ([32]byte, error) {
|
||||
var out [32]byte
|
||||
func (bk *MessageBackupKey) GetHMACKey() ([MessageBackupKeyBytesLength]byte, error) {
|
||||
var out messageBackupKeyBytes
|
||||
signalFfiError := C.signal_message_backup_key_get_hmac_key(
|
||||
(*[32]C.uint8_t)(unsafe.Pointer(&out)),
|
||||
out.cFixedArray(),
|
||||
bk.constPtr(),
|
||||
)
|
||||
runtime.KeepAlive(bk)
|
||||
if signalFfiError != nil {
|
||||
return out, wrapError(signalFfiError)
|
||||
return [MessageBackupKeyBytesLength]byte(out), wrapError(signalFfiError)
|
||||
}
|
||||
return out, nil
|
||||
return [MessageBackupKeyBytesLength]byte(out), nil
|
||||
}
|
||||
|
||||
func (bk *MessageBackupKey) GetAESKey() ([32]byte, error) {
|
||||
var out [32]byte
|
||||
func (bk *MessageBackupKey) GetAESKey() ([MessageBackupKeyBytesLength]byte, error) {
|
||||
var out messageBackupKeyBytes
|
||||
signalFfiError := C.signal_message_backup_key_get_aes_key(
|
||||
(*[32]C.uint8_t)(unsafe.Pointer(&out)),
|
||||
out.cFixedArray(),
|
||||
bk.constPtr(),
|
||||
)
|
||||
runtime.KeepAlive(bk)
|
||||
if signalFfiError != nil {
|
||||
return out, wrapError(signalFfiError)
|
||||
return [MessageBackupKeyBytesLength]byte(out), wrapError(signalFfiError)
|
||||
}
|
||||
return out, nil
|
||||
return [MessageBackupKeyBytesLength]byte(out), nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ func DecryptPreKey(ctx context.Context, preKeyMessage *PreKeyMessage, fromAddres
|
|||
)
|
||||
runtime.KeepAlive(preKeyMessage)
|
||||
runtime.KeepAlive(fromAddress)
|
||||
runtime.KeepAlive(localAddress)
|
||||
if signalFfiError != nil {
|
||||
return nil, callbackCtx.wrapError(signalFfiError)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ func ProcessPreKeyBundle(ctx context.Context, bundle *PreKeyBundle, forAddress,
|
|||
)
|
||||
runtime.KeepAlive(bundle)
|
||||
runtime.KeepAlive(forAddress)
|
||||
runtime.KeepAlive(localAddress)
|
||||
return callbackCtx.wrapError(signalFfiError)
|
||||
}
|
||||
|
||||
|
|
@ -118,10 +119,10 @@ func (pkb *PreKeyBundle) constPtr() C.SignalConstPointerPreKeyBundle {
|
|||
func (pkb *PreKeyBundle) Clone() (*PreKeyBundle, error) {
|
||||
var cloned C.SignalMutPointerPreKeyBundle
|
||||
signalFfiError := C.signal_pre_key_bundle_clone(&cloned, pkb.constPtr())
|
||||
runtime.KeepAlive(pkb)
|
||||
if signalFfiError != nil {
|
||||
return nil, wrapError(signalFfiError)
|
||||
}
|
||||
runtime.KeepAlive(pkb)
|
||||
return wrapPreKeyBundle(cloned.raw), nil
|
||||
}
|
||||
|
||||
|
|
@ -137,9 +138,9 @@ func (pkb *PreKeyBundle) CancelFinalizer() {
|
|||
func (pkb *PreKeyBundle) GetIdentityKey() (*IdentityKey, error) {
|
||||
var pk C.SignalMutPointerPublicKey
|
||||
signalFfiError := C.signal_pre_key_bundle_get_identity_key(&pk, pkb.constPtr())
|
||||
runtime.KeepAlive(pkb)
|
||||
if signalFfiError != nil {
|
||||
return nil, wrapError(signalFfiError)
|
||||
}
|
||||
runtime.KeepAlive(pkb)
|
||||
return NewIdentityKeyFromPublicKey(wrapPublicKey(pk.raw))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import "C"
|
|||
import (
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"unsafe"
|
||||
|
||||
|
|
@ -32,12 +33,38 @@ import (
|
|||
"go.mau.fi/util/random"
|
||||
)
|
||||
|
||||
const ProfileKeyLength = C.SignalPROFILE_KEY_LEN
|
||||
const ProfileKeyLength = 32
|
||||
const AccessKeyLength = 16
|
||||
const ProfileKeyVersionLength = 64
|
||||
|
||||
type ProfileKey [ProfileKeyLength]byte
|
||||
type ProfileKeyCommitment [C.SignalPROFILE_KEY_COMMITMENT_LEN]byte
|
||||
type ProfileKeyVersion [C.SignalPROFILE_KEY_VERSION_ENCODED_LEN]byte
|
||||
type AccessKey [C.SignalACCESS_KEY_LEN]byte
|
||||
type ProfileKeyCommitment = fixedArray97
|
||||
type ProfileKeyVersion [ProfileKeyVersionLength]byte
|
||||
type AccessKey [AccessKeyLength]byte
|
||||
|
||||
func (pk *ProfileKey) cFixedArray() *C.SignalType_FixedArray32_uint8_t {
|
||||
return (*C.SignalType_FixedArray32_uint8_t)(unsafe.Pointer(pk))
|
||||
}
|
||||
|
||||
func (pk *ProfileKey) cConstFixedArray() cFixedArray32Compat {
|
||||
return cFixedArray32Compat(pk.cFixedArray())
|
||||
}
|
||||
|
||||
func (pkv *ProfileKeyVersion) cFixedArray() *C.SignalType_FixedArray64_uint8_t {
|
||||
return (*C.SignalType_FixedArray64_uint8_t)(unsafe.Pointer(pkv))
|
||||
}
|
||||
|
||||
func (pkv *ProfileKeyVersion) cConstFixedArray() cFixedArray64Compat {
|
||||
return cFixedArray64Compat(pkv.cFixedArray())
|
||||
}
|
||||
|
||||
func (ak *AccessKey) cFixedArray() *C.SignalType_FixedArray16_uint8_t {
|
||||
return (*C.SignalType_FixedArray16_uint8_t)(unsafe.Pointer(ak))
|
||||
}
|
||||
|
||||
func (ak *AccessKey) cConstFixedArray() cFixedArray16Compat {
|
||||
return cFixedArray16Compat(ak.cFixedArray())
|
||||
}
|
||||
|
||||
func DeserializeProfileKey(bytes []byte) (*ProfileKey, error) {
|
||||
if len(bytes) == 0 {
|
||||
|
|
@ -73,7 +100,7 @@ func (ak *AccessKey) Xor(other *AccessKey) *AccessKey {
|
|||
return ak
|
||||
}
|
||||
var result AccessKey
|
||||
for i := 0; i < C.SignalACCESS_KEY_LEN; i++ {
|
||||
for i := 0; i < AccessKeyLength; i++ {
|
||||
result[i] = ak[i] ^ other[i]
|
||||
}
|
||||
return &result
|
||||
|
|
@ -84,13 +111,12 @@ func (ak *AccessKey) String() string {
|
|||
}
|
||||
|
||||
func (pk *ProfileKey) GetCommitment(u uuid.UUID) (*ProfileKeyCommitment, error) {
|
||||
c_result := [C.SignalPROFILE_KEY_COMMITMENT_LEN]C.uchar{}
|
||||
c_profileKey := (*[C.SignalPROFILE_KEY_LEN]C.uchar)(unsafe.Pointer(pk))
|
||||
c_uuid := NewACIServiceID(u).CFixedBytes()
|
||||
var result ProfileKeyCommitment
|
||||
c_uuid := NewACIServiceID(u).cConstFixedArray()
|
||||
|
||||
signalFfiError := C.signal_profile_key_get_commitment(
|
||||
&c_result,
|
||||
c_profileKey,
|
||||
result.cFixedArray(),
|
||||
pk.cConstFixedArray(),
|
||||
c_uuid,
|
||||
)
|
||||
runtime.KeepAlive(pk)
|
||||
|
|
@ -100,19 +126,16 @@ func (pk *ProfileKey) GetCommitment(u uuid.UUID) (*ProfileKeyCommitment, error)
|
|||
return nil, wrapError(signalFfiError)
|
||||
}
|
||||
|
||||
var result ProfileKeyCommitment
|
||||
copy(result[:], C.GoBytes(unsafe.Pointer(&c_result), C.int(C.SignalPROFILE_KEY_COMMITMENT_LEN)))
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
func (pk *ProfileKey) GetProfileKeyVersion(u uuid.UUID) (*ProfileKeyVersion, error) {
|
||||
c_result := [C.SignalPROFILE_KEY_VERSION_ENCODED_LEN]C.uchar{}
|
||||
c_profileKey := (*[C.SignalPROFILE_KEY_LEN]C.uchar)(unsafe.Pointer(pk))
|
||||
c_uuid := NewACIServiceID(u).CFixedBytes()
|
||||
var result ProfileKeyVersion
|
||||
c_uuid := NewACIServiceID(u).cConstFixedArray()
|
||||
|
||||
signalFfiError := C.signal_profile_key_get_profile_key_version(
|
||||
&c_result,
|
||||
c_profileKey,
|
||||
result.cFixedArray(),
|
||||
pk.cConstFixedArray(),
|
||||
c_uuid,
|
||||
)
|
||||
runtime.KeepAlive(pk)
|
||||
|
|
@ -122,18 +145,15 @@ func (pk *ProfileKey) GetProfileKeyVersion(u uuid.UUID) (*ProfileKeyVersion, err
|
|||
return nil, wrapError(signalFfiError)
|
||||
}
|
||||
|
||||
var result ProfileKeyVersion
|
||||
copy(result[:], C.GoBytes(unsafe.Pointer(&c_result), C.int(C.SignalPROFILE_KEY_VERSION_ENCODED_LEN)))
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
func (pk *ProfileKey) DeriveAccessKey() (*AccessKey, error) {
|
||||
c_result := [C.SignalACCESS_KEY_LEN]C.uchar{}
|
||||
c_profileKey := (*[C.SignalPROFILE_KEY_LEN]C.uchar)(unsafe.Pointer(pk))
|
||||
var result AccessKey
|
||||
|
||||
signalFfiError := C.signal_profile_key_derive_access_key(
|
||||
&c_result,
|
||||
c_profileKey,
|
||||
result.cFixedArray(),
|
||||
pk.cConstFixedArray(),
|
||||
)
|
||||
runtime.KeepAlive(pk)
|
||||
|
||||
|
|
@ -141,31 +161,37 @@ func (pk *ProfileKey) DeriveAccessKey() (*AccessKey, error) {
|
|||
return nil, wrapError(signalFfiError)
|
||||
}
|
||||
|
||||
var result AccessKey
|
||||
copy(result[:], C.GoBytes(unsafe.Pointer(&c_result), C.int(C.SignalACCESS_KEY_LEN)))
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
type ProfileKeyCredentialRequestContext [C.SignalPROFILE_KEY_CREDENTIAL_REQUEST_CONTEXT_LEN]byte
|
||||
type ProfileKeyCredentialRequest [C.SignalPROFILE_KEY_CREDENTIAL_REQUEST_LEN]byte
|
||||
const ExpiringProfileKeyCredentialResponseLength = 497
|
||||
|
||||
type ProfileKeyCredentialRequestContext [473]byte
|
||||
type ProfileKeyCredentialRequest = fixedArray329
|
||||
type ProfileKeyCredentialResponse []byte
|
||||
type ProfileKeyCredentialPresentation []byte
|
||||
type ExpiringProfileKeyCredential [C.SignalEXPIRING_PROFILE_KEY_CREDENTIAL_LEN]byte
|
||||
type ExpiringProfileKeyCredentialResponse [C.SignalEXPIRING_PROFILE_KEY_CREDENTIAL_RESPONSE_LEN]byte
|
||||
type ExpiringProfileKeyCredential = fixedArray153
|
||||
type ExpiringProfileKeyCredentialResponse = fixedArray497
|
||||
|
||||
func (p *ProfileKeyCredentialRequestContext) cFixedArray() *C.SignalType_FixedArray473_uint8_t {
|
||||
return (*C.SignalType_FixedArray473_uint8_t)(unsafe.Pointer(p))
|
||||
}
|
||||
|
||||
func (p *ProfileKeyCredentialRequestContext) cConstFixedArray() cFixedArray473Compat {
|
||||
return cFixedArray473Compat(p.cFixedArray())
|
||||
}
|
||||
|
||||
func CreateProfileKeyCredentialRequestContext(serverPublicParams *ServerPublicParams, u uuid.UUID, profileKey ProfileKey) (*ProfileKeyCredentialRequestContext, error) {
|
||||
c_result := [C.SignalPROFILE_KEY_CREDENTIAL_REQUEST_CONTEXT_LEN]C.uchar{}
|
||||
randBytes := [32]byte(random.Bytes(32))
|
||||
c_random := (*[32]C.uchar)(unsafe.Pointer(&randBytes[0]))
|
||||
c_profileKey := (*[C.SignalPROFILE_KEY_LEN]C.uchar)(unsafe.Pointer(&profileKey[0]))
|
||||
c_uuid := NewACIServiceID(u).CFixedBytes()
|
||||
var result ProfileKeyCredentialRequestContext
|
||||
randBytes := Randomness(random.Bytes(RandomnessLength))
|
||||
c_uuid := NewACIServiceID(u).cConstFixedArray()
|
||||
|
||||
signalFfiError := C.signal_server_public_params_create_profile_key_credential_request_context_deterministic(
|
||||
&c_result,
|
||||
result.cFixedArray(),
|
||||
C.SignalConstPointerServerPublicParams{serverPublicParams},
|
||||
c_random,
|
||||
randBytes.cConstFixedArray(),
|
||||
c_uuid,
|
||||
c_profileKey,
|
||||
profileKey.cConstFixedArray(),
|
||||
)
|
||||
runtime.KeepAlive(u)
|
||||
runtime.KeepAlive(profileKey)
|
||||
|
|
@ -173,27 +199,27 @@ func CreateProfileKeyCredentialRequestContext(serverPublicParams *ServerPublicPa
|
|||
if signalFfiError != nil {
|
||||
return nil, wrapError(signalFfiError)
|
||||
}
|
||||
result := ProfileKeyCredentialRequestContext(C.GoBytes(unsafe.Pointer(&c_result), C.int(C.SignalPROFILE_KEY_CREDENTIAL_REQUEST_CONTEXT_LEN)))
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
func (p *ProfileKeyCredentialRequestContext) ProfileKeyCredentialRequestContextGetRequest() (*ProfileKeyCredentialRequest, error) {
|
||||
c_result := [C.SignalPROFILE_KEY_CREDENTIAL_REQUEST_LEN]C.uchar{}
|
||||
c_context := (*[C.SignalPROFILE_KEY_CREDENTIAL_REQUEST_CONTEXT_LEN]C.uchar)(unsafe.Pointer(p))
|
||||
var result ProfileKeyCredentialRequest
|
||||
|
||||
signalFfiError := C.signal_profile_key_credential_request_context_get_request(
|
||||
&c_result,
|
||||
c_context,
|
||||
result.cFixedArray(),
|
||||
p.cConstFixedArray(),
|
||||
)
|
||||
runtime.KeepAlive(p)
|
||||
if signalFfiError != nil {
|
||||
return nil, wrapError(signalFfiError)
|
||||
}
|
||||
result := ProfileKeyCredentialRequest(C.GoBytes(unsafe.Pointer(&c_result), C.int(C.SignalPROFILE_KEY_CREDENTIAL_REQUEST_LEN)))
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
func NewExpiringProfileKeyCredentialResponse(b []byte) (*ExpiringProfileKeyCredentialResponse, error) {
|
||||
if len(b) != ExpiringProfileKeyCredentialResponseLength {
|
||||
return nil, fmt.Errorf("invalid expiring profile key credential response length %d (expected %d)", len(b), ExpiringProfileKeyCredentialResponseLength)
|
||||
}
|
||||
borrowedBuffer := BytesToBuffer(b)
|
||||
signalFfiError := C.signal_expiring_profile_key_credential_response_check_valid_contents(borrowedBuffer)
|
||||
runtime.KeepAlive(b)
|
||||
|
|
@ -205,12 +231,12 @@ func NewExpiringProfileKeyCredentialResponse(b []byte) (*ExpiringProfileKeyCrede
|
|||
}
|
||||
|
||||
func ReceiveExpiringProfileKeyCredential(spp *ServerPublicParams, requestContext *ProfileKeyCredentialRequestContext, response *ExpiringProfileKeyCredentialResponse, currentTimeInSeconds uint64) (*ExpiringProfileKeyCredential, error) {
|
||||
c_credential := [C.SignalEXPIRING_PROFILE_KEY_CREDENTIAL_LEN]C.uchar{}
|
||||
var credential ExpiringProfileKeyCredential
|
||||
signalFfiError := C.signal_server_public_params_receive_expiring_profile_key_credential(
|
||||
&c_credential,
|
||||
credential.cFixedArray(),
|
||||
C.SignalConstPointerServerPublicParams{spp},
|
||||
(*[C.SignalPROFILE_KEY_CREDENTIAL_REQUEST_CONTEXT_LEN]C.uchar)(unsafe.Pointer(requestContext)),
|
||||
(*[C.SignalEXPIRING_PROFILE_KEY_CREDENTIAL_RESPONSE_LEN]C.uchar)(unsafe.Pointer(response)),
|
||||
requestContext.cConstFixedArray(),
|
||||
response.cConstFixedArray(),
|
||||
(C.uint64_t)(currentTimeInSeconds),
|
||||
)
|
||||
runtime.KeepAlive(requestContext)
|
||||
|
|
@ -219,8 +245,6 @@ func ReceiveExpiringProfileKeyCredential(spp *ServerPublicParams, requestContext
|
|||
if signalFfiError != nil {
|
||||
return nil, wrapError(signalFfiError)
|
||||
}
|
||||
credential := ExpiringProfileKeyCredential{}
|
||||
copy(credential[:], C.GoBytes(unsafe.Pointer(&c_credential), C.int(C.SignalEXPIRING_PROFILE_KEY_CREDENTIAL_LEN)))
|
||||
return &credential, nil
|
||||
}
|
||||
|
||||
|
|
@ -231,25 +255,21 @@ func (a ProfileKeyCredentialPresentation) CheckValidContents() error {
|
|||
}
|
||||
|
||||
func (a ProfileKeyCredentialPresentation) UUIDCiphertext() (UUIDCiphertext, error) {
|
||||
out := [C.SignalUUID_CIPHERTEXT_LEN]C.uchar{}
|
||||
signalFfiError := C.signal_profile_key_credential_presentation_get_uuid_ciphertext(&out, BytesToBuffer(a))
|
||||
var out UUIDCiphertext
|
||||
signalFfiError := C.signal_profile_key_credential_presentation_get_uuid_ciphertext(out.cFixedArray(), BytesToBuffer(a))
|
||||
runtime.KeepAlive(a)
|
||||
if signalFfiError != nil {
|
||||
return UUIDCiphertext{}, wrapError(signalFfiError)
|
||||
}
|
||||
var result UUIDCiphertext
|
||||
copy(result[:], C.GoBytes(unsafe.Pointer(&out), C.int(C.SignalUUID_CIPHERTEXT_LEN)))
|
||||
return result, nil
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (a ProfileKeyCredentialPresentation) ProfileKeyCiphertext() (ProfileKeyCiphertext, error) {
|
||||
out := [C.SignalPROFILE_KEY_CIPHERTEXT_LEN]C.uchar{}
|
||||
signalFfiError := C.signal_profile_key_credential_presentation_get_profile_key_ciphertext(&out, BytesToBuffer(a))
|
||||
var out ProfileKeyCiphertext
|
||||
signalFfiError := C.signal_profile_key_credential_presentation_get_profile_key_ciphertext(out.cFixedArray(), BytesToBuffer(a))
|
||||
runtime.KeepAlive(a)
|
||||
if signalFfiError != nil {
|
||||
return ProfileKeyCiphertext{}, wrapError(signalFfiError)
|
||||
}
|
||||
var result ProfileKeyCiphertext
|
||||
copy(result[:], C.GoBytes(unsafe.Pointer(&out), C.int(C.SignalPROFILE_KEY_CIPHERTEXT_LEN)))
|
||||
return result, nil
|
||||
return out, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -169,6 +169,19 @@ const (
|
|||
UnidentifiedSenderMessageContentHintImplicit UnidentifiedSenderMessageContentHint = 2
|
||||
)
|
||||
|
||||
func (hint UnidentifiedSenderMessageContentHint) String() string {
|
||||
switch hint {
|
||||
case UnidentifiedSenderMessageContentHintDefault:
|
||||
return "Default"
|
||||
case UnidentifiedSenderMessageContentHintResendable:
|
||||
return "Resendable"
|
||||
case UnidentifiedSenderMessageContentHintImplicit:
|
||||
return "Implicit"
|
||||
default:
|
||||
return fmt.Sprintf("Unknown(%d)", hint)
|
||||
}
|
||||
}
|
||||
|
||||
type UnidentifiedSenderMessageContent struct {
|
||||
nc noCopy
|
||||
ptr *C.SignalUnidentifiedSenderMessageContent
|
||||
|
|
|
|||
|
|
@ -208,6 +208,7 @@ func (sc *SenderCertificate) Validate(trustRoots []*PublicKey, ts time.Time) (bo
|
|||
C.uint64_t(ts.UnixMilli()),
|
||||
)
|
||||
runtime.KeepAlive(sc)
|
||||
runtime.KeepAlive(trustRoots)
|
||||
runtime.KeepAlive(constRoots)
|
||||
if signalFfiError != nil {
|
||||
return false, wrapError(signalFfiError)
|
||||
|
|
|
|||
|
|
@ -101,6 +101,7 @@ func (sc *SenderKeyDistributionMessage) CancelFinalizer() {
|
|||
func (sc *SenderKeyDistributionMessage) Serialize() ([]byte, error) {
|
||||
var serialized C.SignalOwnedBuffer = C.SignalOwnedBuffer{}
|
||||
signalFfiError := C.signal_sender_key_distribution_message_serialize(&serialized, sc.constPtr())
|
||||
runtime.KeepAlive(sc)
|
||||
if signalFfiError != nil {
|
||||
return nil, wrapError(signalFfiError)
|
||||
}
|
||||
|
|
@ -116,6 +117,7 @@ func (sc *SenderKeyDistributionMessage) Process(ctx context.Context, sender *Add
|
|||
callbackCtx.wrapSenderKeyStore(store),
|
||||
)
|
||||
runtime.KeepAlive(sender)
|
||||
runtime.KeepAlive(sc)
|
||||
if signalFfiError != nil {
|
||||
return callbackCtx.wrapError(signalFfiError)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,15 +24,16 @@ import "C"
|
|||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type ServerPublicParams = C.SignalServerPublicParams
|
||||
type NotarySignature [C.SignalSIGNATURE_LEN]byte
|
||||
type NotarySignature = fixedArray64
|
||||
|
||||
const ServerPublicParamsLength = 673
|
||||
|
||||
func DeserializeServerPublicParams(params []byte) (*ServerPublicParams, error) {
|
||||
if len(params) != C.SignalSERVER_PUBLIC_PARAMS_LEN {
|
||||
return nil, fmt.Errorf("invalid server public params length: %d (expected %d)", len(params), int(C.SignalSERVER_PUBLIC_PARAMS_LEN))
|
||||
if len(params) != ServerPublicParamsLength {
|
||||
return nil, fmt.Errorf("invalid server public params length: %d (expected %d)", len(params), ServerPublicParamsLength)
|
||||
}
|
||||
var out C.SignalMutPointerServerPublicParams
|
||||
signalFfiError := C.signal_server_public_params_deserialize(&out, BytesToBuffer(params[:]))
|
||||
|
|
@ -47,11 +48,10 @@ func ServerPublicParamsVerifySignature(
|
|||
messageBytes []byte,
|
||||
NotarySignature NotarySignature,
|
||||
) error {
|
||||
c_notarySignature := (*[C.SignalSIGNATURE_LEN]C.uint8_t)(unsafe.Pointer(&NotarySignature[0]))
|
||||
signalFfiError := C.signal_server_public_params_verify_signature(
|
||||
C.SignalConstPointerServerPublicParams{serverPublicParams},
|
||||
BytesToBuffer(messageBytes),
|
||||
c_notarySignature,
|
||||
NotarySignature.cConstFixedArray(),
|
||||
)
|
||||
runtime.KeepAlive(messageBytes)
|
||||
return wrapError(signalFfiError)
|
||||
|
|
|
|||
|
|
@ -133,7 +133,10 @@ func (s ServiceID) MarshalZerologObject(e *zerolog.Event) {
|
|||
e.Stringer("uuid", s.UUID)
|
||||
}
|
||||
|
||||
type ServiceIDFixedBytes [17]byte
|
||||
const ServiceIDUUIDLength = 16
|
||||
const ServiceIDFixedBytesLength = 17
|
||||
|
||||
type ServiceIDFixedBytes = fixedArray17
|
||||
|
||||
func (s ServiceID) FixedBytes() *ServiceIDFixedBytes {
|
||||
var result ServiceIDFixedBytes
|
||||
|
|
@ -162,18 +165,18 @@ func ServiceIDFromString(val string) (ServiceID, error) {
|
|||
}
|
||||
|
||||
func ServiceIDFromBytes(bytes []byte) (ServiceID, error) {
|
||||
if len(bytes) == 16 {
|
||||
if len(bytes) == ServiceIDUUIDLength {
|
||||
return NewACIServiceID(uuid.UUID(bytes)), nil
|
||||
} else if len(bytes) == 17 {
|
||||
} else if len(bytes) == ServiceIDFixedBytesLength {
|
||||
return ServiceID{
|
||||
Type: ServiceIDType(bytes[0]),
|
||||
UUID: uuid.UUID(bytes[1:]),
|
||||
}, nil
|
||||
}
|
||||
return EmptyServiceID, fmt.Errorf("invalid ServiceID byte length: %d (expected 16 or 17)", len(bytes))
|
||||
return EmptyServiceID, fmt.Errorf("invalid ServiceID byte length: %d (expected %d or %d)", len(bytes), ServiceIDUUIDLength, ServiceIDFixedBytesLength)
|
||||
}
|
||||
|
||||
func ServiceIDFromCFixedBytes(serviceID *C.SignalServiceIdFixedWidthBinaryBytes) ServiceID {
|
||||
func ServiceIDFromCFixedBytes(serviceID *C.SignalType_FixedArray17_uint8_t) ServiceID {
|
||||
var id ServiceID
|
||||
fixedBytes := (*ServiceIDFixedBytes)(unsafe.Pointer(serviceID))
|
||||
id.Type = ServiceIDType(fixedBytes[0])
|
||||
|
|
@ -181,6 +184,10 @@ func ServiceIDFromCFixedBytes(serviceID *C.SignalServiceIdFixedWidthBinaryBytes)
|
|||
return id
|
||||
}
|
||||
|
||||
func (s ServiceID) CFixedBytes() cPNIType {
|
||||
return cPNIType(unsafe.Pointer(s.FixedBytes()))
|
||||
func (s ServiceID) cFixedArray() *C.SignalType_FixedArray17_uint8_t {
|
||||
return s.FixedBytes().cFixedArray()
|
||||
}
|
||||
|
||||
func (s ServiceID) cConstFixedArray() cFixedArray17Compat {
|
||||
return cFixedArray17Compat(s.cFixedArray())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +0,0 @@
|
|||
//go:build darwin || android || ios || (windows && arm64)
|
||||
|
||||
package libsignalgo
|
||||
|
||||
/*
|
||||
#include "./libsignal-ffi.h"
|
||||
#include <stdlib.h>
|
||||
*/
|
||||
import "C"
|
||||
|
||||
type cPNIType = *C.SignalServiceIdFixedWidthBinaryBytes
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
//go:build !(darwin || android || ios || (windows && arm64))
|
||||
|
||||
package libsignalgo
|
||||
|
||||
/*
|
||||
#include "./libsignal-ffi.h"
|
||||
#include <stdlib.h>
|
||||
*/
|
||||
import "C"
|
||||
|
||||
// Hack for https://github.com/golang/go/issues/7270
|
||||
// The clang version is more correct, but doesn't work with gcc
|
||||
|
||||
type cPNIType = *[17]C.uint8_t
|
||||
|
|
@ -105,7 +105,6 @@ func (sr *SessionRecord) HasCurrentState() (bool, error) {
|
|||
signalFfiError := C.signal_session_record_has_usable_sender_chain(
|
||||
&result,
|
||||
sr.constPtr(),
|
||||
C.double(0.0),
|
||||
C.uint64_t(time.Now().Unix()),
|
||||
)
|
||||
runtime.KeepAlive(sr)
|
||||
|
|
|
|||
5
pkg/libsignalgo/signalversion/version.go
Normal file
5
pkg/libsignalgo/signalversion/version.go
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
// Generated by update-ffi.sh; DO NOT EDIT.
|
||||
|
||||
package signalversion
|
||||
|
||||
const Version = "v0.102.2"
|
||||
|
|
@ -1,11 +1,10 @@
|
|||
#!/bin/sh
|
||||
cd /data
|
||||
export RUSTFLAGS="-Ctarget-feature=-crt-static" RUSTC_WRAPPER=""
|
||||
apk add --no-cache git make cmake protobuf-dev musl-dev g++ clang-dev cbindgen
|
||||
apk add --no-cache git make cmake protobuf-dev musl-dev g++ clang-dev
|
||||
cd libsignal
|
||||
cargo build -p libsignal-ffi --release
|
||||
cbindgen --profile release rust/bridge/ffi -o libsignal-ffi.h
|
||||
cd ..
|
||||
mv libsignal/target/release/libsignal_ffi.a .
|
||||
mv libsignal/libsignal-ffi.h .
|
||||
chown 1000:1000 libsignal_ffi.a libsignal-ffi.h version.go
|
||||
cp libsignal/swift/Sources/SignalFfi/signal_ffi.h libsignal-ffi.h
|
||||
chown 1000:1000 libsignal_ffi.a libsignal-ffi.h
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
#!/bin/bash
|
||||
docker run --rm -itv $(pwd):/data rust:1-alpine /data/update-ffi-docker-inner.sh
|
||||
|
||||
echo "// Generated by update-ffi.sh; DO NOT EDIT." > version.go
|
||||
echo >> version.go
|
||||
echo "package libsignalgo" >> version.go
|
||||
echo >> version.go
|
||||
echo "// Generated by update-ffi.sh; DO NOT EDIT." > signalversion/version.go
|
||||
echo >> signalversion/version.go
|
||||
echo "package signalversion" >> signalversion/version.go
|
||||
echo >> signalversion/version.go
|
||||
cd libsignal
|
||||
echo "const Version = \"$(git describe --tags --always)\"" >> ../version.go
|
||||
echo "const Version = \"$(git describe --tags --always)\"" >> ../signalversion/version.go
|
||||
|
|
|
|||
|
|
@ -12,10 +12,10 @@ if [ ! -d "$LIBSIGNAL_DIRECTORY" ]; then
|
|||
exit 1
|
||||
fi
|
||||
|
||||
echo "// Generated by update-ffi.sh; DO NOT EDIT." > version.go
|
||||
echo >> version.go
|
||||
echo "package libsignalgo" >> version.go
|
||||
echo >> version.go
|
||||
echo "// Generated by update-ffi.sh; DO NOT EDIT." > signalversion/version.go
|
||||
echo >> signalversion/version.go
|
||||
echo "package signalversion" >> signalversion/version.go
|
||||
echo >> signalversion/version.go
|
||||
|
||||
# Store the current working directory
|
||||
ORIGINAL_DIR="$(pwd)"
|
||||
|
|
@ -23,19 +23,16 @@ ORIGINAL_DIR="$(pwd)"
|
|||
# Navigate to libsignal directory
|
||||
cd "$LIBSIGNAL_DIRECTORY"
|
||||
|
||||
echo "const Version = \"$(git describe --tags --always)\"" >> ../version.go
|
||||
echo "const Version = \"$(git describe --tags --always)\"" >> ../signalversion/version.go
|
||||
|
||||
# Build libsignal
|
||||
cargo build -p libsignal-ffi --release
|
||||
|
||||
# Regenerate the header file
|
||||
cbindgen --profile release rust/bridge/ffi -o libsignal-ffi.h
|
||||
|
||||
# Navigate back to the original directory
|
||||
cd "$ORIGINAL_DIR"
|
||||
|
||||
# Copy files from the libsignal directory
|
||||
cp "${LIBSIGNAL_DIRECTORY}/target/release/libsignal_ffi.a" .
|
||||
cp "${LIBSIGNAL_DIRECTORY}/libsignal-ffi.h" .
|
||||
cp "${LIBSIGNAL_DIRECTORY}/swift/Sources/SignalFfi/signal_ffi.h" libsignal-ffi.h
|
||||
|
||||
echo "Files copied successfully."
|
||||
|
|
|
|||
|
|
@ -1,5 +0,0 @@
|
|||
// Generated by update-ffi.sh; DO NOT EDIT.
|
||||
|
||||
package libsignalgo
|
||||
|
||||
const Version = "v0.97.2"
|
||||
|
|
@ -35,7 +35,7 @@ import (
|
|||
"go.mau.fi/mautrix-signal/pkg/msgconv/matrixfmt"
|
||||
"go.mau.fi/mautrix-signal/pkg/signalid"
|
||||
"go.mau.fi/mautrix-signal/pkg/signalmeow"
|
||||
signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf"
|
||||
"go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf/signalpb"
|
||||
)
|
||||
|
||||
func (mc *MessageConverter) ToSignal(
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@ import (
|
|||
"go.mau.fi/util/exslices"
|
||||
"go.mau.fi/util/ptr"
|
||||
|
||||
signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf"
|
||||
"go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf/backuppb"
|
||||
"go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf/signalpb"
|
||||
)
|
||||
|
||||
func boolToInt(b bool) int {
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"mime"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
|
|
@ -42,7 +43,7 @@ import (
|
|||
"go.mau.fi/mautrix-signal/pkg/msgconv/signalfmt"
|
||||
"go.mau.fi/mautrix-signal/pkg/signalid"
|
||||
"go.mau.fi/mautrix-signal/pkg/signalmeow"
|
||||
signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf"
|
||||
"go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf/signalpb"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -569,15 +570,20 @@ func (mc *MessageConverter) reuploadAttachment(ctx context.Context, att *signalp
|
|||
content.Info.Blurhash = att.GetBlurHash()
|
||||
content.Info.AnoaBlurhash = att.GetBlurHash()
|
||||
}
|
||||
switch strings.Split(content.Info.MimeType, "/")[0] {
|
||||
case "image":
|
||||
plainMime, _, _ := mime.ParseMediaType(content.Info.MimeType)
|
||||
// Supported mime types from https://github.com/signalapp/Signal-Desktop/blob/main/ts/util/GoogleChrome.std.ts
|
||||
switch plainMime {
|
||||
case "image/avif", "image/bmp", "image/gif", "image/jpeg", "image/webp", "image/x-xbitmap",
|
||||
"image/vnd.microsoft.icon", "image/ico", "image/icon", "image/x-icon", "image/png", "image/apng":
|
||||
content.MsgType = event.MsgImage
|
||||
case "video":
|
||||
case "video/mp4", "video/ogg", "video/webm":
|
||||
content.MsgType = event.MsgVideo
|
||||
case "audio":
|
||||
content.MsgType = event.MsgAudio
|
||||
default:
|
||||
content.MsgType = event.MsgFile
|
||||
if strings.HasPrefix(plainMime, "audio/") && !strings.HasSuffix(plainMime, "aiff") {
|
||||
content.MsgType = event.MsgAudio
|
||||
} else {
|
||||
content.MsgType = event.MsgFile
|
||||
}
|
||||
}
|
||||
var extra map[string]any
|
||||
if att.GetFlags()&uint32(signalpb.AttachmentPointer_GIF) != 0 {
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ import (
|
|||
|
||||
"go.mau.fi/mautrix-signal/pkg/signalid"
|
||||
"go.mau.fi/mautrix-signal/pkg/signalmeow"
|
||||
signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf"
|
||||
"go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf/signalpb"
|
||||
)
|
||||
|
||||
const StickerSourceID = "signal"
|
||||
|
|
@ -158,18 +158,24 @@ func (mc *MessageConverter) DownloadImagePack(ctx context.Context, url string) (
|
|||
imagesByID[stickerID] = mxc
|
||||
return mxc, nil
|
||||
}
|
||||
duplicateCounter := make(map[string]int)
|
||||
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)
|
||||
if _, alreadyExists := content.Images[shortcode]; alreadyExists {
|
||||
counter, ok := duplicateCounter[shortcode]
|
||||
if !ok {
|
||||
counter = 2
|
||||
} else {
|
||||
counter++
|
||||
}
|
||||
duplicateCounter[shortcode] = counter
|
||||
shortcode = fmt.Sprintf("%s_%d", shortcode, counter)
|
||||
}
|
||||
content.Images[realShortcode] = &event.ImagePackImage{
|
||||
content.Images[shortcode] = &event.ImagePackImage{
|
||||
URL: mxc,
|
||||
Body: sticker.GetEmoji(),
|
||||
Info: &event.FileInfo{
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import (
|
|||
|
||||
"maunium.net/go/mautrix/event"
|
||||
|
||||
signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf"
|
||||
"go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf/signalpb"
|
||||
)
|
||||
|
||||
func Parse(ctx context.Context, parser *HTMLParser, content *event.MessageEventContent) (string, []*signalpb.BodyRange) {
|
||||
|
|
|
|||
|
|
@ -111,22 +111,13 @@ func TestParse_HTML(t *testing.T) {
|
|||
{
|
||||
name: "List",
|
||||
in: "<ul><li>woof</li><li><strong>meow</strong></li><li><pre><code>hmm\nmeow</code></pre></li><li><blockquote>meow<br><h1>meow</h1></blockquote></li></ul>",
|
||||
out: "* woof\n* meow\n* hmm\n meow\n* > meow\n > \n > # meow",
|
||||
out: "* woof\n* meow\n* ```\n hmm\n meow\n ```\n* > meow\n > \n > # meow",
|
||||
ent: signalfmt.BodyRangeList{{
|
||||
Start: 9,
|
||||
Length: 4,
|
||||
Value: signalfmt.StyleBold,
|
||||
}, {
|
||||
Start: 16,
|
||||
Length: 3,
|
||||
Value: signalfmt.StyleMonospace,
|
||||
}, {
|
||||
// FIXME optimally this would be a single range with the previous one so the indent is also monospace
|
||||
Start: 22,
|
||||
Length: 4,
|
||||
Value: signalfmt.StyleMonospace,
|
||||
}, {
|
||||
Start: 45,
|
||||
Start: 57,
|
||||
Length: 6,
|
||||
Value: signalfmt.StyleBold,
|
||||
}},
|
||||
|
|
@ -134,21 +125,13 @@ func TestParse_HTML(t *testing.T) {
|
|||
{
|
||||
name: "OrderedList",
|
||||
in: "<ol start=9><li>woof</li><li><strong>meow</strong></li><li><pre><code>hmm\nmeow</code></pre></li><li><blockquote>meow<br><h1>meow</h1></blockquote></li></ol>",
|
||||
out: "9. woof\n10. meow\n11. hmm\n meow\n12. > meow\n > \n > # meow",
|
||||
out: "9. woof\n10. meow\n11. ```\n hmm\n meow\n ```\n12. > meow\n > \n > # meow",
|
||||
ent: signalfmt.BodyRangeList{{
|
||||
Start: 13,
|
||||
Length: 4,
|
||||
Value: signalfmt.StyleBold,
|
||||
}, {
|
||||
Start: 22,
|
||||
Length: 3,
|
||||
Value: signalfmt.StyleMonospace,
|
||||
}, {
|
||||
Start: 30,
|
||||
Length: 4,
|
||||
Value: signalfmt.StyleMonospace,
|
||||
}, {
|
||||
Start: 59,
|
||||
Start: 75,
|
||||
Length: 6,
|
||||
Value: signalfmt.StyleBold,
|
||||
}},
|
||||
|
|
|
|||
|
|
@ -404,17 +404,17 @@ func (parser *HTMLParser) tagToString(node *html.Node, ctx Context) *EntityStrin
|
|||
return NewEntityString("---")
|
||||
case "pre":
|
||||
var preStr *EntityString
|
||||
//var language string
|
||||
var language string
|
||||
if node.FirstChild != nil && node.FirstChild.Type == html.ElementNode && node.FirstChild.Data == "code" {
|
||||
//class := parser.getAttribute(node.FirstChild, "class")
|
||||
//if strings.HasPrefix(class, "language-") {
|
||||
// language = class[len("language-"):]
|
||||
//}
|
||||
class := parser.getAttribute(node.FirstChild, "class")
|
||||
if strings.HasPrefix(class, "language-") {
|
||||
language = class[len("language-"):]
|
||||
}
|
||||
preStr = parser.nodeToString(node.FirstChild.FirstChild, ctx.WithWhitespace())
|
||||
} else {
|
||||
preStr = parser.nodeToString(node.FirstChild, ctx.WithWhitespace())
|
||||
}
|
||||
return preStr.Format(signalfmt.StyleMonospace)
|
||||
return NewEntityString(fmt.Sprintf("```%s\n", language)).Append(preStr).AppendString("\n```")
|
||||
default:
|
||||
return parser.nodeToTagAwareString(node.FirstChild, ctx)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ import (
|
|||
"maunium.net/go/mautrix/event"
|
||||
"maunium.net/go/mautrix/id"
|
||||
|
||||
signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf"
|
||||
"go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf/signalpb"
|
||||
)
|
||||
|
||||
type UserInfo struct {
|
||||
|
|
@ -86,6 +86,9 @@ func Parse(ctx context.Context, message string, ranges []*signalpb.BodyRange, pa
|
|||
Start: int(*r.Start),
|
||||
Length: int(*r.Length),
|
||||
}.TruncateEnd(maxLength)
|
||||
if br.Start >= maxLength {
|
||||
continue
|
||||
}
|
||||
var mentionACI uuid.UUID
|
||||
switch rv := r.GetAssociatedValue().(type) {
|
||||
case *signalpb.BodyRange_Style_:
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ import (
|
|||
"maunium.net/go/mautrix/id"
|
||||
|
||||
"go.mau.fi/mautrix-signal/pkg/msgconv/signalfmt"
|
||||
signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf"
|
||||
"go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf/signalpb"
|
||||
)
|
||||
|
||||
var realUser = uuid.New()
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import (
|
|||
|
||||
"github.com/google/uuid"
|
||||
|
||||
signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf"
|
||||
"go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf/signalpb"
|
||||
)
|
||||
|
||||
type BodyRangeValue interface {
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ import (
|
|||
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf"
|
||||
"go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf/signalpb"
|
||||
)
|
||||
|
||||
type BodyRange struct {
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ import (
|
|||
"google.golang.org/protobuf/proto"
|
||||
"maunium.net/go/mautrix/event"
|
||||
|
||||
signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf"
|
||||
"go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf/signalpb"
|
||||
)
|
||||
|
||||
func (mc *MessageConverter) convertURLPreviewsToBeeper(ctx context.Context, preview []*signalpb.Preview, attMap AttachmentMap) []*event.BeeperLinkPreview {
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ import (
|
|||
"google.golang.org/protobuf/proto"
|
||||
|
||||
"go.mau.fi/mautrix-signal/pkg/libsignalgo"
|
||||
signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf"
|
||||
"go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf/signalpb"
|
||||
"go.mau.fi/mautrix-signal/pkg/signalmeow/types"
|
||||
"go.mau.fi/mautrix-signal/pkg/signalmeow/web"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ import (
|
|||
|
||||
"go.mau.fi/mautrix-signal/pkg/libsignalgo"
|
||||
"go.mau.fi/mautrix-signal/pkg/signalmeow/events"
|
||||
signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf"
|
||||
"go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf/signalpb"
|
||||
"go.mau.fi/mautrix-signal/pkg/signalmeow/store"
|
||||
"go.mau.fi/mautrix-signal/pkg/signalmeow/types"
|
||||
"go.mau.fi/mautrix-signal/pkg/signalmeow/web"
|
||||
|
|
@ -55,6 +55,7 @@ type Client struct {
|
|||
|
||||
AuthedWS *web.SignalWebsocket
|
||||
UnauthedWS *web.SignalWebsocket
|
||||
GRPC *web.GRPCClient
|
||||
lastConnectionStatus SignalConnectionStatus
|
||||
|
||||
loopCancel context.CancelFunc
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ import (
|
|||
"github.com/rs/zerolog"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf"
|
||||
"go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf/signalpb"
|
||||
"go.mau.fi/mautrix-signal/pkg/signalmeow/types"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ import (
|
|||
"google.golang.org/protobuf/proto"
|
||||
|
||||
"go.mau.fi/mautrix-signal/pkg/libsignalgo"
|
||||
signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf"
|
||||
"go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf/signalpb"
|
||||
)
|
||||
|
||||
func hmacSHA256(key, input []byte) []byte {
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import (
|
|||
"github.com/google/uuid"
|
||||
|
||||
"go.mau.fi/mautrix-signal/pkg/libsignalgo"
|
||||
signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf"
|
||||
"go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf/signalpb"
|
||||
"go.mau.fi/mautrix-signal/pkg/signalmeow/types"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ import (
|
|||
"google.golang.org/protobuf/proto"
|
||||
|
||||
"go.mau.fi/mautrix-signal/pkg/libsignalgo"
|
||||
signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf"
|
||||
"go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf/signalpb"
|
||||
"go.mau.fi/mautrix-signal/pkg/signalmeow/types"
|
||||
"go.mau.fi/mautrix-signal/pkg/signalmeow/web"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,10 +0,0 @@
|
|||
// Copyright 2018 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
package signalservice;
|
||||
|
||||
message DeviceName {
|
||||
optional bytes ephemeralPublic = 1;
|
||||
optional bytes syntheticIv = 2;
|
||||
optional bytes ciphertext = 3;
|
||||
}
|
||||
635
pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.go
generated
635
pkg/signalmeow/protobuf/UnidentifiedDelivery.pb.go
generated
|
|
@ -1,635 +0,0 @@
|
|||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.11
|
||||
// protoc v7.34.1
|
||||
// source: UnidentifiedDelivery.proto
|
||||
|
||||
// Copyright 2018 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
package signalpb
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
unsafe "unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type UnidentifiedSenderMessage_Message_Type int32
|
||||
|
||||
const (
|
||||
// Our parser does not handle reserved in enums: DESKTOP-1569
|
||||
// reserved 1;
|
||||
UnidentifiedSenderMessage_Message_MESSAGE UnidentifiedSenderMessage_Message_Type = 2
|
||||
UnidentifiedSenderMessage_Message_PREKEY_MESSAGE UnidentifiedSenderMessage_Message_Type = 3 // Further cases should line up with Envelope.Type, even though old cases don't.
|
||||
UnidentifiedSenderMessage_Message_SENDERKEY_MESSAGE UnidentifiedSenderMessage_Message_Type = 7
|
||||
UnidentifiedSenderMessage_Message_PLAINTEXT_CONTENT UnidentifiedSenderMessage_Message_Type = 8
|
||||
)
|
||||
|
||||
// Enum value maps for UnidentifiedSenderMessage_Message_Type.
|
||||
var (
|
||||
UnidentifiedSenderMessage_Message_Type_name = map[int32]string{
|
||||
2: "MESSAGE",
|
||||
3: "PREKEY_MESSAGE",
|
||||
7: "SENDERKEY_MESSAGE",
|
||||
8: "PLAINTEXT_CONTENT",
|
||||
}
|
||||
UnidentifiedSenderMessage_Message_Type_value = map[string]int32{
|
||||
"MESSAGE": 2,
|
||||
"PREKEY_MESSAGE": 3,
|
||||
"SENDERKEY_MESSAGE": 7,
|
||||
"PLAINTEXT_CONTENT": 8,
|
||||
}
|
||||
)
|
||||
|
||||
func (x UnidentifiedSenderMessage_Message_Type) Enum() *UnidentifiedSenderMessage_Message_Type {
|
||||
p := new(UnidentifiedSenderMessage_Message_Type)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x UnidentifiedSenderMessage_Message_Type) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (UnidentifiedSenderMessage_Message_Type) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_UnidentifiedDelivery_proto_enumTypes[0].Descriptor()
|
||||
}
|
||||
|
||||
func (UnidentifiedSenderMessage_Message_Type) Type() protoreflect.EnumType {
|
||||
return &file_UnidentifiedDelivery_proto_enumTypes[0]
|
||||
}
|
||||
|
||||
func (x UnidentifiedSenderMessage_Message_Type) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Do not use.
|
||||
func (x *UnidentifiedSenderMessage_Message_Type) UnmarshalJSON(b []byte) error {
|
||||
num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*x = UnidentifiedSenderMessage_Message_Type(num)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Deprecated: Use UnidentifiedSenderMessage_Message_Type.Descriptor instead.
|
||||
func (UnidentifiedSenderMessage_Message_Type) EnumDescriptor() ([]byte, []int) {
|
||||
return file_UnidentifiedDelivery_proto_rawDescGZIP(), []int{2, 0, 0}
|
||||
}
|
||||
|
||||
type UnidentifiedSenderMessage_Message_ContentHint int32
|
||||
|
||||
const (
|
||||
// Show an error immediately; it was important but we can't retry.
|
||||
UnidentifiedSenderMessage_Message_DEFAULT UnidentifiedSenderMessage_Message_ContentHint = 0
|
||||
// Sender will try to resend; delay any error UI if possible
|
||||
UnidentifiedSenderMessage_Message_RESENDABLE UnidentifiedSenderMessage_Message_ContentHint = 1
|
||||
// Don't show any error UI at all; this is something sent implicitly like a typing message or a receipt
|
||||
UnidentifiedSenderMessage_Message_IMPLICIT UnidentifiedSenderMessage_Message_ContentHint = 2
|
||||
)
|
||||
|
||||
// Enum value maps for UnidentifiedSenderMessage_Message_ContentHint.
|
||||
var (
|
||||
UnidentifiedSenderMessage_Message_ContentHint_name = map[int32]string{
|
||||
0: "DEFAULT",
|
||||
1: "RESENDABLE",
|
||||
2: "IMPLICIT",
|
||||
}
|
||||
UnidentifiedSenderMessage_Message_ContentHint_value = map[string]int32{
|
||||
"DEFAULT": 0,
|
||||
"RESENDABLE": 1,
|
||||
"IMPLICIT": 2,
|
||||
}
|
||||
)
|
||||
|
||||
func (x UnidentifiedSenderMessage_Message_ContentHint) Enum() *UnidentifiedSenderMessage_Message_ContentHint {
|
||||
p := new(UnidentifiedSenderMessage_Message_ContentHint)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x UnidentifiedSenderMessage_Message_ContentHint) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (UnidentifiedSenderMessage_Message_ContentHint) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_UnidentifiedDelivery_proto_enumTypes[1].Descriptor()
|
||||
}
|
||||
|
||||
func (UnidentifiedSenderMessage_Message_ContentHint) Type() protoreflect.EnumType {
|
||||
return &file_UnidentifiedDelivery_proto_enumTypes[1]
|
||||
}
|
||||
|
||||
func (x UnidentifiedSenderMessage_Message_ContentHint) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Do not use.
|
||||
func (x *UnidentifiedSenderMessage_Message_ContentHint) UnmarshalJSON(b []byte) error {
|
||||
num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*x = UnidentifiedSenderMessage_Message_ContentHint(num)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Deprecated: Use UnidentifiedSenderMessage_Message_ContentHint.Descriptor instead.
|
||||
func (UnidentifiedSenderMessage_Message_ContentHint) EnumDescriptor() ([]byte, []int) {
|
||||
return file_UnidentifiedDelivery_proto_rawDescGZIP(), []int{2, 0, 1}
|
||||
}
|
||||
|
||||
type ServerCertificate struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Certificate []byte `protobuf:"bytes,1,opt,name=certificate" json:"certificate,omitempty"`
|
||||
Signature []byte `protobuf:"bytes,2,opt,name=signature" json:"signature,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *ServerCertificate) Reset() {
|
||||
*x = ServerCertificate{}
|
||||
mi := &file_UnidentifiedDelivery_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ServerCertificate) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ServerCertificate) ProtoMessage() {}
|
||||
|
||||
func (x *ServerCertificate) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_UnidentifiedDelivery_proto_msgTypes[0]
|
||||
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 ServerCertificate.ProtoReflect.Descriptor instead.
|
||||
func (*ServerCertificate) Descriptor() ([]byte, []int) {
|
||||
return file_UnidentifiedDelivery_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *ServerCertificate) GetCertificate() []byte {
|
||||
if x != nil {
|
||||
return x.Certificate
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ServerCertificate) GetSignature() []byte {
|
||||
if x != nil {
|
||||
return x.Signature
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type SenderCertificate struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Certificate []byte `protobuf:"bytes,1,opt,name=certificate" json:"certificate,omitempty"`
|
||||
Signature []byte `protobuf:"bytes,2,opt,name=signature" json:"signature,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *SenderCertificate) Reset() {
|
||||
*x = SenderCertificate{}
|
||||
mi := &file_UnidentifiedDelivery_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *SenderCertificate) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*SenderCertificate) ProtoMessage() {}
|
||||
|
||||
func (x *SenderCertificate) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_UnidentifiedDelivery_proto_msgTypes[1]
|
||||
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 SenderCertificate.ProtoReflect.Descriptor instead.
|
||||
func (*SenderCertificate) Descriptor() ([]byte, []int) {
|
||||
return file_UnidentifiedDelivery_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *SenderCertificate) GetCertificate() []byte {
|
||||
if x != nil {
|
||||
return x.Certificate
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *SenderCertificate) GetSignature() []byte {
|
||||
if x != nil {
|
||||
return x.Signature
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type UnidentifiedSenderMessage struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
EphemeralPublic []byte `protobuf:"bytes,1,opt,name=ephemeralPublic" json:"ephemeralPublic,omitempty"`
|
||||
EncryptedStatic []byte `protobuf:"bytes,2,opt,name=encryptedStatic" json:"encryptedStatic,omitempty"`
|
||||
EncryptedMessage []byte `protobuf:"bytes,3,opt,name=encryptedMessage" json:"encryptedMessage,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *UnidentifiedSenderMessage) Reset() {
|
||||
*x = UnidentifiedSenderMessage{}
|
||||
mi := &file_UnidentifiedDelivery_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *UnidentifiedSenderMessage) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*UnidentifiedSenderMessage) ProtoMessage() {}
|
||||
|
||||
func (x *UnidentifiedSenderMessage) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_UnidentifiedDelivery_proto_msgTypes[2]
|
||||
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 UnidentifiedSenderMessage.ProtoReflect.Descriptor instead.
|
||||
func (*UnidentifiedSenderMessage) Descriptor() ([]byte, []int) {
|
||||
return file_UnidentifiedDelivery_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
func (x *UnidentifiedSenderMessage) GetEphemeralPublic() []byte {
|
||||
if x != nil {
|
||||
return x.EphemeralPublic
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *UnidentifiedSenderMessage) GetEncryptedStatic() []byte {
|
||||
if x != nil {
|
||||
return x.EncryptedStatic
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *UnidentifiedSenderMessage) GetEncryptedMessage() []byte {
|
||||
if x != nil {
|
||||
return x.EncryptedMessage
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ServerCertificate_Certificate struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Id *uint32 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"`
|
||||
Key []byte `protobuf:"bytes,2,opt,name=key" json:"key,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *ServerCertificate_Certificate) Reset() {
|
||||
*x = ServerCertificate_Certificate{}
|
||||
mi := &file_UnidentifiedDelivery_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ServerCertificate_Certificate) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ServerCertificate_Certificate) ProtoMessage() {}
|
||||
|
||||
func (x *ServerCertificate_Certificate) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_UnidentifiedDelivery_proto_msgTypes[3]
|
||||
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 ServerCertificate_Certificate.ProtoReflect.Descriptor instead.
|
||||
func (*ServerCertificate_Certificate) Descriptor() ([]byte, []int) {
|
||||
return file_UnidentifiedDelivery_proto_rawDescGZIP(), []int{0, 0}
|
||||
}
|
||||
|
||||
func (x *ServerCertificate_Certificate) GetId() uint32 {
|
||||
if x != nil && x.Id != nil {
|
||||
return *x.Id
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ServerCertificate_Certificate) GetKey() []byte {
|
||||
if x != nil {
|
||||
return x.Key
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type SenderCertificate_Certificate struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
SenderE164 *string `protobuf:"bytes,1,opt,name=senderE164" json:"senderE164,omitempty"`
|
||||
SenderUuid *string `protobuf:"bytes,6,opt,name=senderUuid" json:"senderUuid,omitempty"`
|
||||
SenderDevice *uint32 `protobuf:"varint,2,opt,name=senderDevice" json:"senderDevice,omitempty"`
|
||||
Expires *uint64 `protobuf:"fixed64,3,opt,name=expires" json:"expires,omitempty"`
|
||||
IdentityKey []byte `protobuf:"bytes,4,opt,name=identityKey" json:"identityKey,omitempty"`
|
||||
Signer *ServerCertificate `protobuf:"bytes,5,opt,name=signer" json:"signer,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *SenderCertificate_Certificate) Reset() {
|
||||
*x = SenderCertificate_Certificate{}
|
||||
mi := &file_UnidentifiedDelivery_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *SenderCertificate_Certificate) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*SenderCertificate_Certificate) ProtoMessage() {}
|
||||
|
||||
func (x *SenderCertificate_Certificate) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_UnidentifiedDelivery_proto_msgTypes[4]
|
||||
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 SenderCertificate_Certificate.ProtoReflect.Descriptor instead.
|
||||
func (*SenderCertificate_Certificate) Descriptor() ([]byte, []int) {
|
||||
return file_UnidentifiedDelivery_proto_rawDescGZIP(), []int{1, 0}
|
||||
}
|
||||
|
||||
func (x *SenderCertificate_Certificate) GetSenderE164() string {
|
||||
if x != nil && x.SenderE164 != nil {
|
||||
return *x.SenderE164
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *SenderCertificate_Certificate) GetSenderUuid() string {
|
||||
if x != nil && x.SenderUuid != nil {
|
||||
return *x.SenderUuid
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *SenderCertificate_Certificate) GetSenderDevice() uint32 {
|
||||
if x != nil && x.SenderDevice != nil {
|
||||
return *x.SenderDevice
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *SenderCertificate_Certificate) GetExpires() uint64 {
|
||||
if x != nil && x.Expires != nil {
|
||||
return *x.Expires
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *SenderCertificate_Certificate) GetIdentityKey() []byte {
|
||||
if x != nil {
|
||||
return x.IdentityKey
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *SenderCertificate_Certificate) GetSigner() *ServerCertificate {
|
||||
if x != nil {
|
||||
return x.Signer
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type UnidentifiedSenderMessage_Message struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Type *UnidentifiedSenderMessage_Message_Type `protobuf:"varint,1,opt,name=type,enum=signalservice.UnidentifiedSenderMessage_Message_Type" json:"type,omitempty"`
|
||||
SenderCertificate *SenderCertificate `protobuf:"bytes,2,opt,name=senderCertificate" json:"senderCertificate,omitempty"`
|
||||
Content []byte `protobuf:"bytes,3,opt,name=content" json:"content,omitempty"`
|
||||
ContentHint *UnidentifiedSenderMessage_Message_ContentHint `protobuf:"varint,4,opt,name=contentHint,enum=signalservice.UnidentifiedSenderMessage_Message_ContentHint" json:"contentHint,omitempty"`
|
||||
GroupId []byte `protobuf:"bytes,5,opt,name=groupId" json:"groupId,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *UnidentifiedSenderMessage_Message) Reset() {
|
||||
*x = UnidentifiedSenderMessage_Message{}
|
||||
mi := &file_UnidentifiedDelivery_proto_msgTypes[5]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *UnidentifiedSenderMessage_Message) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*UnidentifiedSenderMessage_Message) ProtoMessage() {}
|
||||
|
||||
func (x *UnidentifiedSenderMessage_Message) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_UnidentifiedDelivery_proto_msgTypes[5]
|
||||
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 UnidentifiedSenderMessage_Message.ProtoReflect.Descriptor instead.
|
||||
func (*UnidentifiedSenderMessage_Message) Descriptor() ([]byte, []int) {
|
||||
return file_UnidentifiedDelivery_proto_rawDescGZIP(), []int{2, 0}
|
||||
}
|
||||
|
||||
func (x *UnidentifiedSenderMessage_Message) GetType() UnidentifiedSenderMessage_Message_Type {
|
||||
if x != nil && x.Type != nil {
|
||||
return *x.Type
|
||||
}
|
||||
return UnidentifiedSenderMessage_Message_MESSAGE
|
||||
}
|
||||
|
||||
func (x *UnidentifiedSenderMessage_Message) GetSenderCertificate() *SenderCertificate {
|
||||
if x != nil {
|
||||
return x.SenderCertificate
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *UnidentifiedSenderMessage_Message) GetContent() []byte {
|
||||
if x != nil {
|
||||
return x.Content
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *UnidentifiedSenderMessage_Message) GetContentHint() UnidentifiedSenderMessage_Message_ContentHint {
|
||||
if x != nil && x.ContentHint != nil {
|
||||
return *x.ContentHint
|
||||
}
|
||||
return UnidentifiedSenderMessage_Message_DEFAULT
|
||||
}
|
||||
|
||||
func (x *UnidentifiedSenderMessage_Message) GetGroupId() []byte {
|
||||
if x != nil {
|
||||
return x.GroupId
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_UnidentifiedDelivery_proto protoreflect.FileDescriptor
|
||||
|
||||
const file_UnidentifiedDelivery_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"\x1aUnidentifiedDelivery.proto\x12\rsignalservice\"\x84\x01\n" +
|
||||
"\x11ServerCertificate\x12 \n" +
|
||||
"\vcertificate\x18\x01 \x01(\fR\vcertificate\x12\x1c\n" +
|
||||
"\tsignature\x18\x02 \x01(\fR\tsignature\x1a/\n" +
|
||||
"\vCertificate\x12\x0e\n" +
|
||||
"\x02id\x18\x01 \x01(\rR\x02id\x12\x10\n" +
|
||||
"\x03key\x18\x02 \x01(\fR\x03key\"\xbd\x02\n" +
|
||||
"\x11SenderCertificate\x12 \n" +
|
||||
"\vcertificate\x18\x01 \x01(\fR\vcertificate\x12\x1c\n" +
|
||||
"\tsignature\x18\x02 \x01(\fR\tsignature\x1a\xe7\x01\n" +
|
||||
"\vCertificate\x12\x1e\n" +
|
||||
"\n" +
|
||||
"senderE164\x18\x01 \x01(\tR\n" +
|
||||
"senderE164\x12\x1e\n" +
|
||||
"\n" +
|
||||
"senderUuid\x18\x06 \x01(\tR\n" +
|
||||
"senderUuid\x12\"\n" +
|
||||
"\fsenderDevice\x18\x02 \x01(\rR\fsenderDevice\x12\x18\n" +
|
||||
"\aexpires\x18\x03 \x01(\x06R\aexpires\x12 \n" +
|
||||
"\videntityKey\x18\x04 \x01(\fR\videntityKey\x128\n" +
|
||||
"\x06signer\x18\x05 \x01(\v2 .signalservice.ServerCertificateR\x06signer\"\xe7\x04\n" +
|
||||
"\x19UnidentifiedSenderMessage\x12(\n" +
|
||||
"\x0fephemeralPublic\x18\x01 \x01(\fR\x0fephemeralPublic\x12(\n" +
|
||||
"\x0fencryptedStatic\x18\x02 \x01(\fR\x0fencryptedStatic\x12*\n" +
|
||||
"\x10encryptedMessage\x18\x03 \x01(\fR\x10encryptedMessage\x1a\xc9\x03\n" +
|
||||
"\aMessage\x12I\n" +
|
||||
"\x04type\x18\x01 \x01(\x0e25.signalservice.UnidentifiedSenderMessage.Message.TypeR\x04type\x12N\n" +
|
||||
"\x11senderCertificate\x18\x02 \x01(\v2 .signalservice.SenderCertificateR\x11senderCertificate\x12\x18\n" +
|
||||
"\acontent\x18\x03 \x01(\fR\acontent\x12^\n" +
|
||||
"\vcontentHint\x18\x04 \x01(\x0e2<.signalservice.UnidentifiedSenderMessage.Message.ContentHintR\vcontentHint\x12\x18\n" +
|
||||
"\agroupId\x18\x05 \x01(\fR\agroupId\"U\n" +
|
||||
"\x04Type\x12\v\n" +
|
||||
"\aMESSAGE\x10\x02\x12\x12\n" +
|
||||
"\x0ePREKEY_MESSAGE\x10\x03\x12\x15\n" +
|
||||
"\x11SENDERKEY_MESSAGE\x10\a\x12\x15\n" +
|
||||
"\x11PLAINTEXT_CONTENT\x10\b\"8\n" +
|
||||
"\vContentHint\x12\v\n" +
|
||||
"\aDEFAULT\x10\x00\x12\x0e\n" +
|
||||
"\n" +
|
||||
"RESENDABLE\x10\x01\x12\f\n" +
|
||||
"\bIMPLICIT\x10\x02B6\n" +
|
||||
"%org.whispersystems.libsignal.protocolB\rWhisperProtos"
|
||||
|
||||
var (
|
||||
file_UnidentifiedDelivery_proto_rawDescOnce sync.Once
|
||||
file_UnidentifiedDelivery_proto_rawDescData []byte
|
||||
)
|
||||
|
||||
func file_UnidentifiedDelivery_proto_rawDescGZIP() []byte {
|
||||
file_UnidentifiedDelivery_proto_rawDescOnce.Do(func() {
|
||||
file_UnidentifiedDelivery_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_UnidentifiedDelivery_proto_rawDesc), len(file_UnidentifiedDelivery_proto_rawDesc)))
|
||||
})
|
||||
return file_UnidentifiedDelivery_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_UnidentifiedDelivery_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
|
||||
var file_UnidentifiedDelivery_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
|
||||
var file_UnidentifiedDelivery_proto_goTypes = []any{
|
||||
(UnidentifiedSenderMessage_Message_Type)(0), // 0: signalservice.UnidentifiedSenderMessage.Message.Type
|
||||
(UnidentifiedSenderMessage_Message_ContentHint)(0), // 1: signalservice.UnidentifiedSenderMessage.Message.ContentHint
|
||||
(*ServerCertificate)(nil), // 2: signalservice.ServerCertificate
|
||||
(*SenderCertificate)(nil), // 3: signalservice.SenderCertificate
|
||||
(*UnidentifiedSenderMessage)(nil), // 4: signalservice.UnidentifiedSenderMessage
|
||||
(*ServerCertificate_Certificate)(nil), // 5: signalservice.ServerCertificate.Certificate
|
||||
(*SenderCertificate_Certificate)(nil), // 6: signalservice.SenderCertificate.Certificate
|
||||
(*UnidentifiedSenderMessage_Message)(nil), // 7: signalservice.UnidentifiedSenderMessage.Message
|
||||
}
|
||||
var file_UnidentifiedDelivery_proto_depIdxs = []int32{
|
||||
2, // 0: signalservice.SenderCertificate.Certificate.signer:type_name -> signalservice.ServerCertificate
|
||||
0, // 1: signalservice.UnidentifiedSenderMessage.Message.type:type_name -> signalservice.UnidentifiedSenderMessage.Message.Type
|
||||
3, // 2: signalservice.UnidentifiedSenderMessage.Message.senderCertificate:type_name -> signalservice.SenderCertificate
|
||||
1, // 3: signalservice.UnidentifiedSenderMessage.Message.contentHint:type_name -> signalservice.UnidentifiedSenderMessage.Message.ContentHint
|
||||
4, // [4:4] is the sub-list for method output_type
|
||||
4, // [4:4] is the sub-list for method input_type
|
||||
4, // [4:4] is the sub-list for extension type_name
|
||||
4, // [4:4] is the sub-list for extension extendee
|
||||
0, // [0:4] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_UnidentifiedDelivery_proto_init() }
|
||||
func file_UnidentifiedDelivery_proto_init() {
|
||||
if File_UnidentifiedDelivery_proto != nil {
|
||||
return
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_UnidentifiedDelivery_proto_rawDesc), len(file_UnidentifiedDelivery_proto_rawDesc)),
|
||||
NumEnums: 2,
|
||||
NumMessages: 6,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_UnidentifiedDelivery_proto_goTypes,
|
||||
DependencyIndexes: file_UnidentifiedDelivery_proto_depIdxs,
|
||||
EnumInfos: file_UnidentifiedDelivery_proto_enumTypes,
|
||||
MessageInfos: file_UnidentifiedDelivery_proto_msgTypes,
|
||||
}.Build()
|
||||
File_UnidentifiedDelivery_proto = out.File
|
||||
file_UnidentifiedDelivery_proto_goTypes = nil
|
||||
file_UnidentifiedDelivery_proto_depIdxs = nil
|
||||
}
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
// Copyright 2018 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
package signalservice;
|
||||
|
||||
option java_package = "org.whispersystems.libsignal.protocol";
|
||||
option java_outer_classname = "WhisperProtos";
|
||||
|
||||
message ServerCertificate {
|
||||
message Certificate {
|
||||
optional uint32 id = 1;
|
||||
optional bytes key = 2;
|
||||
}
|
||||
|
||||
optional bytes certificate = 1;
|
||||
optional bytes signature = 2;
|
||||
}
|
||||
|
||||
message SenderCertificate {
|
||||
message Certificate {
|
||||
optional string senderE164 = 1;
|
||||
optional string senderUuid = 6;
|
||||
optional uint32 senderDevice = 2;
|
||||
optional fixed64 expires = 3;
|
||||
optional bytes identityKey = 4;
|
||||
optional ServerCertificate signer = 5;
|
||||
}
|
||||
|
||||
optional bytes certificate = 1;
|
||||
optional bytes signature = 2;
|
||||
}
|
||||
|
||||
message UnidentifiedSenderMessage {
|
||||
|
||||
message Message {
|
||||
enum Type {
|
||||
// Our parser does not handle reserved in enums: DESKTOP-1569
|
||||
// reserved 1;
|
||||
MESSAGE = 2;
|
||||
PREKEY_MESSAGE = 3;
|
||||
// Further cases should line up with Envelope.Type, even though old cases don't.
|
||||
|
||||
// reserved 3 to 6;
|
||||
|
||||
SENDERKEY_MESSAGE = 7;
|
||||
PLAINTEXT_CONTENT = 8;
|
||||
}
|
||||
|
||||
enum ContentHint {
|
||||
// Show an error immediately; it was important but we can't retry.
|
||||
DEFAULT = 0;
|
||||
|
||||
// Sender will try to resend; delay any error UI if possible
|
||||
RESENDABLE = 1;
|
||||
|
||||
// Don't show any error UI at all; this is something sent implicitly like a typing message or a receipt
|
||||
IMPLICIT = 2;
|
||||
}
|
||||
|
||||
optional Type type = 1;
|
||||
optional SenderCertificate senderCertificate = 2;
|
||||
optional bytes content = 3;
|
||||
optional ContentHint contentHint = 4;
|
||||
optional bytes groupId = 5;
|
||||
}
|
||||
|
||||
optional bytes ephemeralPublic = 1;
|
||||
optional bytes encryptedStatic = 2;
|
||||
optional bytes encryptedMessage = 3;
|
||||
}
|
||||
1061
pkg/signalmeow/protobuf/backuppb/Backup.pb.go
generated
1061
pkg/signalmeow/protobuf/backuppb/Backup.pb.go
generated
File diff suppressed because it is too large
Load diff
BIN
pkg/signalmeow/protobuf/backuppb/Backup.pb.raw
generated
BIN
pkg/signalmeow/protobuf/backuppb/Backup.pb.raw
generated
Binary file not shown.
|
|
@ -103,6 +103,12 @@ message AccountData {
|
|||
}
|
||||
|
||||
message AccountSettings {
|
||||
enum UnreadBadgeType {
|
||||
UNKNOWN_BADGE_TYPE = 0; // Interpret as "Unread messages"
|
||||
UNREAD_MESSAGES = 1;
|
||||
UNREAD_CHATS = 2;
|
||||
}
|
||||
|
||||
bool readReceipts = 1;
|
||||
bool sealedSenderIndicators = 2;
|
||||
bool typingIndicators = 3;
|
||||
|
|
@ -136,6 +142,14 @@ message AccountData {
|
|||
bool allowSealedSenderFromAnyone = 30;
|
||||
bool allowAutomaticKeyVerification = 31;
|
||||
bool hasSeenAdminDeleteEducationDialog = 32;
|
||||
UnreadBadgeType unreadBadgeType = 33; // Only used in ios/desktop
|
||||
optional bool includeMutedChatsInBadge = 34; // Only used in ios/desktop. If unset, consider this disabled
|
||||
optional bool reactionNotifications = 35; // If unset, consider this enabled
|
||||
optional bool notifyForCallsIfMuted = 36; // If unset, consider this disabled
|
||||
optional bool notifyForMentionsIfMuted = 37; // If unset, consider this enabled
|
||||
optional bool notifyForRepliesIfMuted = 38; // If unset, consider this enabled
|
||||
optional bool showUnreadReminders = 39; // If unset, consider this enabled
|
||||
optional bool notifyWhenContactJoins = 40; // If unset, consider this disabled
|
||||
}
|
||||
|
||||
message SubscriberData {
|
||||
|
|
@ -272,6 +286,7 @@ message Contact {
|
|||
string systemNickname = 20;
|
||||
optional AvatarColor avatarColor = 21;
|
||||
optional bytes keyTransparencyData = 22;
|
||||
uint64 blockedAtTimestamp = 23; // if `blocked` is true, 0 means unknown block time
|
||||
}
|
||||
|
||||
message Group {
|
||||
|
|
@ -288,6 +303,7 @@ message Group {
|
|||
GroupSnapshot snapshot = 5;
|
||||
bool blocked = 6;
|
||||
optional AvatarColor avatarColor = 7;
|
||||
uint64 blockedAtTimestamp = 8; // if `blocked` is true, 0 means unknown block time
|
||||
|
||||
// These are simply plaintext copies of the groups proto from Groups.proto.
|
||||
// They should be kept completely in-sync with Groups.proto.
|
||||
|
|
@ -385,9 +401,13 @@ message Chat {
|
|||
optional uint64 expirationTimerMs = 5;
|
||||
optional uint64 muteUntilMs = 6; // INT64_MAX (2^63 - 1) = "always muted".
|
||||
bool markedUnread = 7;
|
||||
bool dontNotifyForMentionsIfMuted = 8;
|
||||
bool dontNotifyForMentionsIfMuted = 8; // will be deprecated in favor of [notifyForMentionsIfMuted]
|
||||
ChatStyle style = 9;
|
||||
uint32 expireTimerVersion = 10;
|
||||
optional bool notifyForCallsIfMuted = 11; // If unset, use default global settings
|
||||
optional bool notifyForMentionsIfMuted = 12; // If unset, use default global settings. Only for groups. If [dontNotifyForMentionsIfMuted] is true, this should be initialized to false.
|
||||
optional bool notifyForRepliesIfMuted = 13; // If unset, use default global settings. Only for groups.
|
||||
optional bool showUnreadReminders = 14; // If unset, use default global settings
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,19 +1,18 @@
|
|||
#!/bin/sh
|
||||
PKG_IMPORT_PATH="go.mau.fi/mautrix-signal/pkg/signalmeow/signalpb"
|
||||
for file in *.proto
|
||||
do
|
||||
# Requires https://go-review.googlesource.com/c/protobuf/+/369634
|
||||
protoc --go_out=. \
|
||||
--go_opt=M${file}=$PKG_IMPORT_PATH \
|
||||
--go_opt=paths=source_relative \
|
||||
$file
|
||||
#!/bin/bash
|
||||
cd $(dirname "$0")
|
||||
BASE_IMPORT_PATH="go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf"
|
||||
opts=()
|
||||
for file in */*.proto; do
|
||||
opts+=("--go_opt=M${file}=${BASE_IMPORT_PATH}/$(dirname "$file")")
|
||||
opts+=("--go-grpc_opt=M${file}=${BASE_IMPORT_PATH}/$(dirname "$file")")
|
||||
done
|
||||
protoc --go_out=. \
|
||||
--go_opt=Mbackuppb/Backup.proto=$PKG_IMPORT_PATH/backuppb \
|
||||
--go_opt=paths=source_relative \
|
||||
backuppb/Backup.proto
|
||||
protoc --go_out=. \
|
||||
--go_opt=Mcds2pb/cds2.proto=$PKG_IMPORT_PATH/cds2pb \
|
||||
--go_opt=paths=source_relative \
|
||||
cds2pb/cds2.proto
|
||||
for file in org/signal/chat/*.proto; do
|
||||
file_without_ext=$(basename "$file" .proto)
|
||||
opts+=("--go_opt=M${file}=${BASE_IMPORT_PATH}/rpc/${file_without_ext}")
|
||||
opts+=("--go-grpc_opt=M${file}=${BASE_IMPORT_PATH}/rpc/${file_without_ext}")
|
||||
done
|
||||
protoc --go_out=. --go-grpc_out=. \
|
||||
--go_opt=module=$BASE_IMPORT_PATH \
|
||||
--go-grpc_opt=module=$BASE_IMPORT_PATH "${opts[@]}" \
|
||||
*/*.proto org/signal/chat/*.proto
|
||||
pre-commit run -a
|
||||
|
|
|
|||
608
pkg/signalmeow/protobuf/org/signal/chat/account.proto
Normal file
608
pkg/signalmeow/protobuf/org/signal/chat/account.proto
Normal file
|
|
@ -0,0 +1,608 @@
|
|||
syntax = "proto3";
|
||||
|
||||
option java_multiple_files = true;
|
||||
|
||||
package org.signal.chat.account;
|
||||
|
||||
import "google/protobuf/empty.proto";
|
||||
|
||||
import "org/signal/chat/common.proto";
|
||||
import "org/signal/chat/errors.proto";
|
||||
import "org/signal/chat/messages.proto";
|
||||
import "org/signal/chat/require.proto";
|
||||
import "org/signal/chat/tag.proto";
|
||||
|
||||
// Provides methods for working with Signal accounts.
|
||||
service Accounts {
|
||||
option (require.auth) = AUTH_ONLY_AUTHENTICATED;
|
||||
|
||||
// Returns basic identifiers for the authenticated account.
|
||||
rpc GetAccountIdentity(GetAccountIdentityRequest) returns (GetAccountIdentityResponse) {}
|
||||
|
||||
// Returns entitlements for the authenticated account.
|
||||
rpc GetEntitlements(GetEntitlementsRequest) returns (GetEntitlementsResponse) {}
|
||||
|
||||
// Deletes the authenticated account, purging all associated data in the
|
||||
// process.
|
||||
rpc DeleteAccount(DeleteAccountRequest) returns (DeleteAccountResponse) {}
|
||||
|
||||
// Sets the registration lock secret for the authenticated account. To remove
|
||||
// a registration lock, please use `ClearRegistrationLock`.
|
||||
rpc SetRegistrationLock(SetRegistrationLockRequest) returns (SetRegistrationLockResponse) {}
|
||||
|
||||
// Removes any registration lock credentials from the authenticated account.
|
||||
rpc ClearRegistrationLock(ClearRegistrationLockRequest) returns (ClearRegistrationLockResponse) {}
|
||||
|
||||
// Attempts to reserve one of multiple given username hashes. Reserved
|
||||
// usernames may be claimed later via `ConfirmUsernameHash`.
|
||||
rpc ReserveUsernameHash(ReserveUsernameHashRequest) returns (ReserveUsernameHashResponse) {}
|
||||
|
||||
// Sets the username hash/encrypted username to a previously-reserved value
|
||||
// (see `ReserveUsernameHash`).
|
||||
rpc ConfirmUsernameHash(ConfirmUsernameHashRequest) returns (ConfirmUsernameHashResponse) {}
|
||||
|
||||
// Clears the current username hash, ciphertext, and link for the
|
||||
// authenticated user.
|
||||
rpc DeleteUsernameHash(DeleteUsernameHashRequest) returns (DeleteUsernameHashResponse) {}
|
||||
|
||||
// Associates the given username ciphertext with the account, replacing any
|
||||
// previously stored ciphertext. A new link handle will optionally be created,
|
||||
// and the link handle to use will be returned in any event.
|
||||
rpc SetUsernameLink(SetUsernameLinkRequest) returns (SetUsernameLinkResponse) {}
|
||||
|
||||
// Clears any username link associated with the authenticated account.
|
||||
rpc DeleteUsernameLink(DeleteUsernameLinkRequest) returns (DeleteUsernameLinkResponse) {}
|
||||
|
||||
// Configures "unidentified access" keys and preferences for the authenticated
|
||||
// account. Other users permitted to interact with this account anonymously
|
||||
// may take actions like fetching pre-keys and profiles for this account or
|
||||
// sending sealed-sender messages without providing identifying credentials.
|
||||
rpc ConfigureUnidentifiedAccess(ConfigureUnidentifiedAccessRequest) returns (ConfigureUnidentifiedAccessResponse) {}
|
||||
|
||||
// Sets whether the authenticated account may be discovered by phone number
|
||||
// via the Contact Discovery Service (CDS).
|
||||
rpc SetDiscoverableByPhoneNumber(SetDiscoverableByPhoneNumberRequest) returns (SetDiscoverableByPhoneNumberResponse) {}
|
||||
|
||||
// Sets the registration recovery password for the authenticated account.
|
||||
rpc SetRegistrationRecoveryPassword(SetRegistrationRecoveryPasswordRequest) returns (SetRegistrationRecoveryPasswordResponse) {}
|
||||
|
||||
// Store a public key used to issue and verify zero-knowledge (anonymous) credentials for the account.
|
||||
rpc SetZkCredentialKey(SetZkCredentialKeyRequest) returns (SetZkCredentialKeyResponse) {}
|
||||
|
||||
// Changes the phone number associated with the authenticated account.
|
||||
rpc ChangeNumber(ChangeNumberRequest) returns (ChangeNumberResponse) {}
|
||||
|
||||
// Produces a report of non-ephemeral account data stored by the service
|
||||
rpc GetAccountDataReport(GetAccountDataReportRequest) returns (GetAccountDataReportResponse) {}
|
||||
|
||||
// Gets the capabilities for the authenticated account.
|
||||
rpc GetCapabilities(GetCapabilitiesRequest) returns (GetCapabilitiesResponse) {}
|
||||
|
||||
// Generates and stores a pending TOTP key for the authenticated account.
|
||||
// To "activate" the key, callers must call the `ConfirmTotpKey` endpoint.
|
||||
rpc GenerateTotpKey(GenerateTotpKeyRequest) returns (GenerateTotpKeyResponse) {}
|
||||
|
||||
// Confirms that the caller has stored and can derive one-time passwords from
|
||||
// a pending TOTP key generated via `GenerateTotpKey` and stores/activates the
|
||||
// key for the caller's account
|
||||
rpc ConfirmTotpKey(ConfirmTotpKeyRequest) returns (ConfirmTotpKeyResponse) {}
|
||||
|
||||
// Returns a list of confirmed TOTP keys for the authenticated account
|
||||
rpc ListTotpKeys(ListTotpKeysRequest) returns (ListTotpKeysResponse) {}
|
||||
|
||||
// Updates encrypted, user-supplied metadata (e.g. a human-readable name and
|
||||
// creation timestamp) for an existing, confirmed TOTP key
|
||||
rpc SetTotpKeyMetadata(SetTotpKeyMetadataRequest) returns (SetTotpKeyMetadataResponse) {}
|
||||
|
||||
// Removes a TOTP from the authenticated account
|
||||
rpc RemoveTotpKey(RemoveTotpKeyRequest) returns (RemoveTotpKeyResponse) {}
|
||||
}
|
||||
|
||||
// Provides methods for looking up Signal accounts. Callers must not provide
|
||||
// identifying credentials when calling methods in this service.
|
||||
service AccountsAnonymous {
|
||||
option (require.auth) = AUTH_ONLY_ANONYMOUS;
|
||||
|
||||
// Checks whether an account with the given service identifier exists.
|
||||
rpc CheckAccountExistence(CheckAccountExistenceRequest) returns (CheckAccountExistenceResponse) {}
|
||||
|
||||
// Finds the service identifier of the account associated with the given
|
||||
// username hash.
|
||||
rpc LookupUsernameHash(LookupUsernameHashRequest) returns (LookupUsernameHashResponse) {}
|
||||
|
||||
// Finds the encrypted username identified by a given username link handle.
|
||||
rpc LookupUsernameLink(LookupUsernameLinkRequest) returns (LookupUsernameLinkResponse) {}
|
||||
|
||||
// Gets the publicly-visible capabilities enabled on the account identified by
|
||||
// the provided ACI.
|
||||
rpc GetCapabilities(GetCapabilitiesAnonymousRequest) returns (GetCapabilitiesAnonymousResponse) {}
|
||||
}
|
||||
|
||||
message GetAccountIdentityRequest {
|
||||
}
|
||||
|
||||
message GetAccountIdentityResponse {
|
||||
// The identifiers for the authenticated account.
|
||||
common.AccountIdentifiers account_identifiers = 1;
|
||||
}
|
||||
|
||||
message GetEntitlementsRequest {
|
||||
}
|
||||
|
||||
message GetEntitlementsResponse {
|
||||
message BadgeEntitlement {
|
||||
// The id of the badge the account is entitled. Metadata to display for
|
||||
// badges may be obtained by cross-referencing badge ids with
|
||||
// RemoteConfiguration.GetBadges.
|
||||
string badge_id = 1;
|
||||
// When the badge expires, in number of seconds since epoch
|
||||
uint64 expiration_epoch_seconds = 2;
|
||||
// Whether the badge is currently configured to be visible
|
||||
bool visible = 3;
|
||||
}
|
||||
|
||||
message BackupEntitlement {
|
||||
// The backup level of the account
|
||||
uint64 level = 1;
|
||||
// When the backup entitlement expires, in number of seconds since epoch
|
||||
uint64 expiration_epoch_seconds = 2;
|
||||
}
|
||||
|
||||
// Active badges added via Donations.redeemReceipt
|
||||
repeated BadgeEntitlement badges = 1;
|
||||
|
||||
// If present, the backup level set via Backups.redeemReceipt
|
||||
BackupEntitlement backup = 2;
|
||||
}
|
||||
|
||||
message DeleteAccountRequest {
|
||||
}
|
||||
|
||||
message DeleteAccountResponse {
|
||||
}
|
||||
|
||||
message SetRegistrationLockRequest {
|
||||
// The new registration lock secret for the authenticated account.
|
||||
bytes registration_lock = 1 [(require.exactlySize) = 32];
|
||||
}
|
||||
|
||||
message SetRegistrationLockResponse {
|
||||
}
|
||||
|
||||
message ClearRegistrationLockRequest {
|
||||
}
|
||||
|
||||
message ClearRegistrationLockResponse {
|
||||
}
|
||||
|
||||
message ReserveUsernameHashRequest {
|
||||
// A prioritized list of username hashes to attempt to reserve.
|
||||
repeated bytes username_hashes = 1 [(require.size) = {min: 1, max: 20}, (require.each) = {exactlySize: 32}];
|
||||
}
|
||||
|
||||
message UsernameNotAvailable {}
|
||||
|
||||
message ReserveUsernameHashResponse {
|
||||
oneof response {
|
||||
// The first username hash that was available (and actually reserved).
|
||||
bytes username_hash = 1;
|
||||
|
||||
// Indicates that, of all of the candidate hashes provided, none were
|
||||
// available. Callers may generate a new set of hashes and and retry.
|
||||
UsernameNotAvailable username_not_available = 2 [(tag.reason) = "username_not_available"];
|
||||
}
|
||||
}
|
||||
|
||||
message ConfirmUsernameHashRequest {
|
||||
// The username hash to claim for the authenticated account.
|
||||
bytes username_hash = 1 [(require.exactlySize) = 32];
|
||||
|
||||
// A zero-knowledge proof that the given username hash was generated by the
|
||||
// Signal username algorithm.
|
||||
bytes zk_proof = 2 [(require.nonEmpty) = true];
|
||||
|
||||
// The ciphertext of the chosen username for use in public-facing contexts
|
||||
// (e.g. links and QR codes).
|
||||
bytes username_ciphertext = 3 [(require.size) = {min: 1, max: 128}];
|
||||
}
|
||||
|
||||
message ConfirmUsernameHashResponse {
|
||||
message ConfirmedUsernameHash {
|
||||
reserved 1; // username_hash
|
||||
|
||||
// The server-generated username link handle for the newly-confirmed username.
|
||||
bytes username_link_handle = 2;
|
||||
}
|
||||
|
||||
oneof response {
|
||||
// The details of the successfully confirmed username.
|
||||
ConfirmedUsernameHash confirmed_username_hash = 1;
|
||||
|
||||
// The provided hash was not reserved for the account.
|
||||
errors.FailedPrecondition reservation_not_found = 2 [(tag.reason) = "reservation_not_found"];
|
||||
|
||||
// The reservation has lapsed and the requested username has been claimed by
|
||||
// another caller.
|
||||
UsernameNotAvailable username_not_available = 3 [(tag.reason) = "username_not_available"];
|
||||
}
|
||||
}
|
||||
|
||||
message DeleteUsernameHashRequest {
|
||||
}
|
||||
|
||||
message DeleteUsernameHashResponse {
|
||||
}
|
||||
|
||||
message SetUsernameLinkRequest {
|
||||
// The username ciphertext for which to generate a new link handle.
|
||||
bytes username_ciphertext = 1 [(require.size) = {min: 1, max: 128}];
|
||||
|
||||
// If true and the account already had an encrypted username stored, the
|
||||
// existing link handle will be reused. Otherwise a new link handle will be
|
||||
// created.
|
||||
bool keep_link_handle = 2;
|
||||
}
|
||||
|
||||
|
||||
message SetUsernameLinkResponse {
|
||||
oneof response {
|
||||
// A new link handle for the given username ciphertext.
|
||||
bytes username_link_handle = 1;
|
||||
|
||||
// The authenticated account did not have a username set.
|
||||
errors.FailedPrecondition no_username_set = 2 [(tag.reason) = "no_username_set"];
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
message DeleteUsernameLinkRequest {
|
||||
}
|
||||
|
||||
message DeleteUsernameLinkResponse {
|
||||
}
|
||||
|
||||
message ConfigureUnidentifiedAccessRequest {
|
||||
oneof configuration {
|
||||
// The key that other users must provide to interact with this account
|
||||
// anonymously (i.e. to retrieve keys or profiles or to send messages) unless
|
||||
// unrestricted unidentified access is permitted. Must be present if
|
||||
// unrestricted unidentified access is not allowed.
|
||||
bytes unidentified_access_key = 1 [(require.exactlySize) = 16];
|
||||
|
||||
// If set, any user may interact with this account anonymously without
|
||||
// providing an unidentified access key. Otherwise, users must provide the
|
||||
// given unidentified access key to interact with this account anonymously.
|
||||
// Setting unrestricted unidentified access will clear any existing
|
||||
// unidentified_access_key
|
||||
google.protobuf.Empty allow_unrestricted_unidentified_access = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message ConfigureUnidentifiedAccessResponse {
|
||||
}
|
||||
|
||||
message SetDiscoverableByPhoneNumberRequest {
|
||||
// If true, the authenticated account may be discovered by phone number via
|
||||
// the Contact Discovery Service (CDS). Otherwise, other users must discover
|
||||
// this account by other means (i.e. by username).
|
||||
bool discoverable_by_phone_number = 1;
|
||||
}
|
||||
|
||||
message SetDiscoverableByPhoneNumberResponse {
|
||||
}
|
||||
|
||||
message SetRegistrationRecoveryPasswordRequest {
|
||||
// The new registration recovery password for the authenticated account.
|
||||
bytes registration_recovery_password = 1 [(require.exactlySize) = 32];
|
||||
}
|
||||
|
||||
message SetRegistrationRecoveryPasswordResponse {
|
||||
}
|
||||
|
||||
message CheckAccountExistenceRequest {
|
||||
// The service identifier of an account that may or may not exist.
|
||||
common.ServiceIdentifier service_identifier = 1;
|
||||
}
|
||||
|
||||
message CheckAccountExistenceResponse {
|
||||
// True if an account exists with the given service identifier or false if no
|
||||
// account was found.
|
||||
bool account_exists = 1;
|
||||
}
|
||||
|
||||
message LookupUsernameHashRequest {
|
||||
// A 32-byte username hash for which to find an account.
|
||||
bytes username_hash = 1 [(require.exactlySize) = 32];
|
||||
}
|
||||
|
||||
message LookupUsernameHashResponse {
|
||||
oneof response {
|
||||
// The service identifier associated with the provided username hash.
|
||||
common.ServiceIdentifier service_identifier = 1;
|
||||
|
||||
// No account was found for the provided username hash.
|
||||
errors.NotFound not_found = 2 [(tag.reason) = "not_found"];
|
||||
}
|
||||
}
|
||||
|
||||
message LookupUsernameLinkRequest {
|
||||
// The link handle for which to find an encrypted username. Link handles are
|
||||
// 16-byte representations of UUIDs.
|
||||
bytes username_link_handle = 1 [(require.exactlySize) = 16];
|
||||
}
|
||||
|
||||
message LookupUsernameLinkResponse {
|
||||
oneof response {
|
||||
// The ciphertext of the username identified by the provided link handle.
|
||||
bytes username_ciphertext = 1;
|
||||
|
||||
|
||||
// No username was found for the provided link handle.
|
||||
errors.NotFound not_found = 2 [(tag.reason) = "not_found"];
|
||||
}
|
||||
}
|
||||
|
||||
message SetZkCredentialKeyRequest {
|
||||
// A serialized libsignal ZkCredentialPublicKey
|
||||
bytes public_key = 1 [(require.exactlySize) = 33];
|
||||
}
|
||||
|
||||
message SetZkCredentialKeyResponse {
|
||||
// A random, non-zero, value that must be included in credential requests using the key.
|
||||
//
|
||||
// This value allows the server to ratchet the resulting binding identity,
|
||||
// as reverting to the previous key will result in a new rotation ID.
|
||||
uint64 rotation_id = 1;
|
||||
}
|
||||
|
||||
message ChangeNumberRequest {
|
||||
// A means of authenticating the change-number request for the new phone
|
||||
// number. Exactly one must be provided.
|
||||
oneof verification {
|
||||
// A verified registration session ID (as returned by the registration
|
||||
// service) for the new phone number.
|
||||
bytes session_id = 1 [(require.nonEmpty) = true];
|
||||
|
||||
// A registration recovery password for the new phone number.
|
||||
bytes recovery_password = 2 [(require.exactlySize) = 32];
|
||||
}
|
||||
|
||||
// The new phone number for the authenticated account.
|
||||
string number = 3 [(require.e164) = true];
|
||||
|
||||
// The registration lock secret for the new phone number, if the account
|
||||
// associated with the new phone number has a registration lock configured.
|
||||
bytes registration_lock = 4 [(require.exactlySize) = 0, (require.exactlySize) = 32];
|
||||
|
||||
// The new public identity key to use for the phone-number identity (PNI)
|
||||
// associated with the new phone number.
|
||||
bytes pni_identity_key = 5 [(require.nonEmpty) = true];
|
||||
|
||||
// Synchronization messages to send to companion devices to supply the private
|
||||
// keys associated with the new identity key and their new pre-keys. Exactly
|
||||
// one message must be supplied for each device other than the sending
|
||||
// (primary) device. May be omitted if no companion devices are linked to the
|
||||
// account.
|
||||
messages.IndividualRecipientMessageBundle device_messages = 6;
|
||||
|
||||
// A new signed EC pre-key for each device on the account, including the
|
||||
// sending device, keyed by device ID. Each must be accompanied by a valid
|
||||
// signature from the identity key in this request.
|
||||
map<uint32, common.EcSignedPreKey> device_pni_signed_pre_keys = 7;
|
||||
|
||||
// A new signed post-quantum last-resort pre-key for each device on the
|
||||
// account, including the sending device, keyed by device ID. Each must be
|
||||
// accompanied by a valid signature from the identity key in this request.
|
||||
map<uint32, common.KemSignedPreKey> device_pni_pq_last_resort_pre_keys = 8;
|
||||
|
||||
// The new phone-number-identity registration ID for each device on the
|
||||
// account, including the sending device, keyed by device ID.
|
||||
map<uint32, uint32> pni_registration_ids = 9;
|
||||
}
|
||||
|
||||
message ChangeNumberResponse {
|
||||
oneof response {
|
||||
// The identifiers of the account after the successful
|
||||
// number change.
|
||||
common.AccountIdentifiers account_identifiers = 1;
|
||||
|
||||
// Mismatched number of devices or device ids in 'devices to notify' list
|
||||
messages.MismatchedDevices mismatched_devices = 2 [(tag.reason) = "mismatched_devices"];
|
||||
|
||||
// The account associated with the new phone number has a registration lock,
|
||||
// and the provided registration lock secret was missing or incorrect.
|
||||
RegistrationLockFailure registration_lock_failure = 3 [(tag.reason) = "registration_lock_failure"];
|
||||
|
||||
// Mismatched registration ids in 'devices to notify' list
|
||||
StaleDevices stale_devices = 4 [(tag.reason) = "stale_devices"];
|
||||
|
||||
// One or more device messages was too large
|
||||
errors.FailedPrecondition message_too_large = 5 [(tag.reason) = "message_too_large"];
|
||||
|
||||
// The registration session is unverified
|
||||
errors.FailedPrecondition unverified_registration_session = 6 [(tag.reason) = "unverified_registration_session"];
|
||||
|
||||
// The number does not match the registration session, or the registration session is invalid
|
||||
errors.FailedPrecondition invalid_registration_session = 7 [(tag.reason) = "invalid_registration_session"];
|
||||
|
||||
errors.FailedPrecondition recovery_password_verification_failed = 8 [(tag.reason) = "recovery_password_verification_failed"];
|
||||
}
|
||||
}
|
||||
|
||||
// Information about the current Registration lock and SVR credentials. With a correct PIN, the credentials can
|
||||
// be used to recover the secret used to derive the registration lock password.
|
||||
message RegistrationLockFailure {
|
||||
// Time remaining in milliseconds before the existing registration lock expires
|
||||
uint64 time_remaining_millis = 1;
|
||||
|
||||
// Credentials that can be used with SVR2
|
||||
ExternalServiceCredentials svr2_credentials = 2;
|
||||
}
|
||||
|
||||
// A username/password pair for authenticating with an external service.
|
||||
message ExternalServiceCredentials {
|
||||
// A username that can be presented to authenticate with the external service.
|
||||
string username = 1;
|
||||
|
||||
// A password that can be presented to authenticate with the external service.
|
||||
string password = 2;
|
||||
}
|
||||
|
||||
// A list of devices that are linked to the account but presented a stale
|
||||
// registration ID (indicating the device has likely been replaced by another
|
||||
// device).
|
||||
message StaleDevices {
|
||||
// The IDs of devices that are no longer active.
|
||||
repeated uint32 stale_devices = 1 [(require.each) = {range: {max: 0x7f}}];
|
||||
}
|
||||
|
||||
message GetAccountDataReportRequest {
|
||||
}
|
||||
|
||||
message GetAccountDataReportResponse {
|
||||
// The JSON representation of the data report
|
||||
string json = 3;
|
||||
// A plaintext representation of the data report
|
||||
string text = 4;
|
||||
}
|
||||
|
||||
message GetCapabilitiesRequest {
|
||||
}
|
||||
|
||||
message Capabilities {
|
||||
// A list of capabilities enabled on the account.
|
||||
repeated common.DeviceCapability capabilities = 1;
|
||||
}
|
||||
|
||||
message GetCapabilitiesResponse {
|
||||
// A list of capabilities enabled on the account.
|
||||
Capabilities capabilities = 1;
|
||||
}
|
||||
|
||||
message GetCapabilitiesAnonymousRequest {
|
||||
// The ACI of the account for which to get capabilities.
|
||||
common.ServiceIdentifier account_identifier = 1 [(require.present) = true, (require.identityType) = IDENTITY_TYPE_ACI];
|
||||
|
||||
oneof authentication {
|
||||
// The unidentified access key for the targeted account.
|
||||
bytes unidentified_access_key = 2 [(require.exactlySize) = 16];
|
||||
|
||||
// A group send endorsement token for the targeted account.
|
||||
bytes group_send_token = 3 [(require.nonEmpty) = true];
|
||||
}
|
||||
}
|
||||
|
||||
message GetCapabilitiesAnonymousResponse {
|
||||
oneof response {
|
||||
// A list of capabilities enabled on the account.
|
||||
Capabilities capabilities = 1;
|
||||
errors.NotFound not_found = 2 [(tag.reason) = "not_found"];
|
||||
errors.FailedUnidentifiedAuthorization failed_unidentified_authorization = 3 [(tag.reason) = "failed_unidentified_authorization"];
|
||||
}
|
||||
}
|
||||
|
||||
message TotpParameters {
|
||||
// The HMAC algorithm (e.g. "HmacSHA256") used by the TOTP generator
|
||||
string algorithm = 1;
|
||||
|
||||
// The length of one-time passwords (in decimal digits) produced and expected
|
||||
// by the TOTP generator
|
||||
uint32 password_length = 2;
|
||||
|
||||
// The time step (in seconds) used by the TOTP generator
|
||||
uint32 time_step_seconds = 3;
|
||||
}
|
||||
|
||||
message GenerateTotpKeyRequest {
|
||||
}
|
||||
|
||||
message GenerateTotpKeyResponse {
|
||||
message KeyGenerated {
|
||||
// The raw TOTP key
|
||||
bytes key = 1;
|
||||
|
||||
// The TOTP parameters associated with the generated key
|
||||
TotpParameters totp_parameters = 2;
|
||||
}
|
||||
|
||||
oneof response {
|
||||
// A new, pending TOTP key has been generated and added to the authenticated
|
||||
// account
|
||||
KeyGenerated key_generated = 1;
|
||||
|
||||
// The authenticated account already has too many TOTP keys, and the caller
|
||||
// must remove one before adding more
|
||||
errors.FailedPrecondition too_many_totp_keys = 2 [(tag.reason) = "too_many_totp_keys"];
|
||||
}
|
||||
}
|
||||
|
||||
message ConfirmTotpKeyRequest {
|
||||
// A one-time password derived from the current pending TOTP key
|
||||
uint32 one_time_password = 1;
|
||||
|
||||
// The ciphertext of user-provided metadata (presumably including a
|
||||
// human-readable name and creation timestamp) to be attached to the
|
||||
// newly-confirmed key
|
||||
bytes metadata_ciphertext = 2 [(require.exactlySize) = 160];
|
||||
}
|
||||
|
||||
message ConfirmTotpKeyResponse {
|
||||
message KeyConfirmed {
|
||||
// The account-specific identifier for the newly-confirmed TOTP key
|
||||
uint32 key_id = 1;
|
||||
}
|
||||
|
||||
oneof response {
|
||||
// The provided one-time password was accepted and the pending TOTP key was
|
||||
// stored with the provided name ciphertext
|
||||
KeyConfirmed key_confirmed = 1;
|
||||
|
||||
// The provided one-time password was not valid for any reason (including
|
||||
// incorrect passwords, misaligned clocks, or missing account records)
|
||||
errors.FailedPrecondition one_time_password_not_verified = 2 [(tag.reason) = "one_time_password_not_verified"];
|
||||
}
|
||||
}
|
||||
|
||||
message ListTotpKeysRequest {}
|
||||
|
||||
message ListTotpKeysResponse {
|
||||
message TotpKeyMetadata {
|
||||
// The user-provided ciphertext for metadata associated with this TOTP key
|
||||
bytes metadata_ciphertext = 1;
|
||||
|
||||
// The TOTP parameters associated with this key
|
||||
TotpParameters totp_parameters = 2;
|
||||
}
|
||||
|
||||
map<int32, TotpKeyMetadata> keys = 1;
|
||||
}
|
||||
|
||||
message SetTotpKeyMetadataRequest {
|
||||
// The account-specific identifier of the TOTP key to modify
|
||||
uint32 key_id = 1;
|
||||
|
||||
// The ciphertext of the new user-provided metadata to be attached to the
|
||||
// identified key
|
||||
bytes metadata_ciphertext = 2 [(require.exactlySize) = 160];
|
||||
}
|
||||
|
||||
message SetTotpKeyMetadataResponse {
|
||||
message MetadataUpdated {
|
||||
}
|
||||
|
||||
oneof response {
|
||||
// New metadata was stored for the identified TOTP key
|
||||
MetadataUpdated metadata_updated = 1;
|
||||
|
||||
// No TOTP was found with the given ID
|
||||
errors.NotFound key_not_found = 2 [(tag.reason) = "key_not_found"];
|
||||
}
|
||||
}
|
||||
|
||||
message RemoveTotpKeyRequest {
|
||||
// The account-specific identifier of the TOTP key to remove
|
||||
uint32 key_id = 1;
|
||||
}
|
||||
|
||||
message RemoveTotpKeyResponse {
|
||||
}
|
||||
58
pkg/signalmeow/protobuf/org/signal/chat/attachments.proto
Normal file
58
pkg/signalmeow/protobuf/org/signal/chat/attachments.proto
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright 2026 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
option java_multiple_files = true;
|
||||
|
||||
package org.signal.chat.attachments;
|
||||
|
||||
import "org/signal/chat/common.proto";
|
||||
import "org/signal/chat/require.proto";
|
||||
import "org/signal/chat/errors.proto";
|
||||
import "org/signal/chat/tag.proto";
|
||||
|
||||
service Attachments {
|
||||
option (require.auth) = AUTH_ONLY_AUTHENTICATED;
|
||||
|
||||
// Retrieve an upload form that can be used to perform a resumable upload
|
||||
rpc GetUploadForm(GetUploadFormRequest) returns (GetUploadFormResponse) {}
|
||||
|
||||
// Retrieve an upload form that can be used to upload a sticker pack
|
||||
rpc GetStickerUploadForm(GetStickerUploadFormRequest) returns (GetStickerUploadFormResponse) {}
|
||||
}
|
||||
|
||||
message GetUploadFormRequest {
|
||||
// The length of the attachment for the requested upload form. Uploads
|
||||
// performed with this form will be limited to the provided length.
|
||||
uint64 uploadLength = 1 [(require.range) = {min: 1}];
|
||||
}
|
||||
|
||||
message GetUploadFormResponse {
|
||||
oneof outcome {
|
||||
common.UploadForm upload_form = 1;
|
||||
|
||||
// The request size was larger than the maximum supported upload size. The
|
||||
// maximum upload size is subject to change and is governed by
|
||||
// `global.attachments.maxBytes`
|
||||
errors.FailedPrecondition exceeds_max_upload_length = 2 [(tag.reason) = "oversize_upload"];
|
||||
}
|
||||
}
|
||||
|
||||
message GetStickerUploadFormRequest {
|
||||
// The number of stickers in the sticker pack to upload
|
||||
uint32 sticker_count = 1 [(require.range) = {min: 1, max: 201}];
|
||||
}
|
||||
|
||||
message GetStickerUploadFormResponse {
|
||||
// A randomly-generated ID for the new sticker pack
|
||||
string pack_id = 1;
|
||||
|
||||
// An upload form clients must use to upload a manifest for the sticker pack
|
||||
common.S3UploadForm manifest_upload_form = 2;
|
||||
|
||||
// Upload forms for individual stickers within the sticker pack
|
||||
repeated common.S3UploadForm sticker_upload_forms = 3;
|
||||
}
|
||||
554
pkg/signalmeow/protobuf/org/signal/chat/backups.proto
Normal file
554
pkg/signalmeow/protobuf/org/signal/chat/backups.proto
Normal file
|
|
@ -0,0 +1,554 @@
|
|||
/*
|
||||
* Copyright 2024 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
option java_multiple_files = true;
|
||||
|
||||
package org.signal.chat.backup;
|
||||
|
||||
import "google/protobuf/empty.proto";
|
||||
import "org/signal/chat/common.proto";
|
||||
import "org/signal/chat/errors.proto";
|
||||
import "org/signal/chat/require.proto";
|
||||
import "org/signal/chat/tag.proto";
|
||||
|
||||
// Service for backup operations that require account authentication.
|
||||
//
|
||||
// Most actual backup operations operate on the backup-id and cannot be linked
|
||||
// to the caller's account, but setting up anonymous credentials and changing
|
||||
// backup tier requires account authentication.
|
||||
service Backups {
|
||||
option (require.auth) = AUTH_ONLY_AUTHENTICATED;
|
||||
|
||||
// Set (blinded) backup-id(s) for the account.
|
||||
//
|
||||
// Each account may have a single active backup-id for each credential type
|
||||
// that can be used to store and retrieve backups. Once the backup-id is set,
|
||||
// BackupAuthCredentials can be generated using GetBackupAuthCredentials.
|
||||
//
|
||||
// The blinded backup-id and the key-pair used to blind it must be derived
|
||||
// from a recoverable secret.
|
||||
//
|
||||
// At least one of the credential types must be set on the request.
|
||||
// Only the primary device can set a blinded backup-id.
|
||||
rpc SetBackupId(SetBackupIdRequest) returns (SetBackupIdResponse) {}
|
||||
|
||||
// Redeem a receipt acquired from /v1/subscription/{subscriberId}/receipt_credentials
|
||||
// to mark the account as eligible for the paid backup tier.
|
||||
//
|
||||
// After successful redemption, subsequent requests to
|
||||
// GetBackupAuthCredentials will return credentials with the level on the
|
||||
// provided receipt until the expiration time on the receipt.
|
||||
rpc RedeemReceipt(RedeemReceiptRequest) returns (RedeemReceiptResponse) {}
|
||||
|
||||
// After setting a blinded backup-id with PUT /v1/archives/, this fetches
|
||||
// credentials that can be used to perform operations against that backup-id.
|
||||
// Clients may (and should) request up to 7 days of credentials at a time.
|
||||
//
|
||||
// The redemption_start and redemption_end seconds must be UTC day aligned, and
|
||||
// must not span more than 7 days.
|
||||
//
|
||||
// Each credential contains a receipt level which indicates the backup level
|
||||
// the credential is good for. If the account has paid backup access that
|
||||
// expires at some point in the provided redemption window, credentials with
|
||||
// redemption times after the expiration may be on a lower backup level.
|
||||
//
|
||||
// Clients must validate the receipt level on the credential matches a known
|
||||
// receipt level before using it.
|
||||
rpc GetBackupAuthCredentials(GetBackupAuthCredentialsRequest) returns (GetBackupAuthCredentialsResponse) {}
|
||||
}
|
||||
|
||||
message SetBackupIdRequest {
|
||||
// A BackupAuthCredentialRequest containing a blinded encrypted backup-id,
|
||||
// encoded in standard padded base64. This backup-id should be used for
|
||||
// message backups only, and must have the message backup type set on the
|
||||
// credential. If absent, the message credential request will not be updated.
|
||||
bytes messages_backup_auth_credential_request = 1;
|
||||
|
||||
// A BackupAuthCredentialRequest containing a blinded encrypted backup-id,
|
||||
// encoded in standard padded base64. This backup-id should be used for
|
||||
// media only, and must have the media type set on the credential. If absent,
|
||||
// the media credential request will not be updated.
|
||||
bytes media_backup_auth_credential_request = 2;
|
||||
}
|
||||
|
||||
message SetBackupIdResponse {}
|
||||
|
||||
|
||||
message RedeemReceiptRequest {
|
||||
// Presentation for a previously acquired receipt, serialized with libsignal
|
||||
bytes presentation = 1;
|
||||
}
|
||||
|
||||
message RedeemReceiptResponse {
|
||||
oneof response {
|
||||
// The receipt was successfully redeemed
|
||||
google.protobuf.Empty success = 1;
|
||||
|
||||
// The target account does not have a backup-id commitment
|
||||
errors.FailedPrecondition account_missing_commitment = 2 [(tag.reason) = "account_missing_commitment"];
|
||||
|
||||
// The provided receipt presentation was malformed or expired
|
||||
errors.FailedPrecondition invalid_receipt = 3 [(tag.reason) = "invalid_receipt"];
|
||||
}
|
||||
}
|
||||
|
||||
message GetBackupAuthCredentialsRequest {
|
||||
// The redemption time for the first credential. This must be a day-aligned
|
||||
// seconds since epoch in UTC.
|
||||
int64 redemption_start = 1 [(require.range).min = 1];
|
||||
|
||||
// The redemption time for the last credential. This must be a day-aligned
|
||||
// seconds since epoch in UTC. The span between redemptionStart and
|
||||
// redemptionEnd must not exceed 7 days.
|
||||
int64 redemption_stop = 2 [(require.range).min = 1];
|
||||
}
|
||||
|
||||
message GetBackupAuthCredentialsResponse {
|
||||
message Credentials {
|
||||
// The requested message backup ZkCredentials indexed by the start of their
|
||||
// validity period. The smallest key should be for the requested
|
||||
// redemption_start, the largest for the requested redemption_end.
|
||||
map<int64, common.ZkCredential> message_credentials = 1;
|
||||
|
||||
// The requested media backup ZkCredentials indexed by the start of their
|
||||
// validity period. The smallest key should be for the requested
|
||||
// redemption_start, the largest for the requested redemption_end.
|
||||
map<int64, common.ZkCredential> media_credentials = 2;
|
||||
}
|
||||
|
||||
// The requested credentials. If absent, there was no existing blinded
|
||||
// backup id associated with the provided account.
|
||||
Credentials credentials = 1;
|
||||
}
|
||||
|
||||
// Service for backup operations with anonymous credentials
|
||||
//
|
||||
// This service never requires account authentication. It instead requires a
|
||||
// backup-id authenticated with an anonymous credential that cannot be linked
|
||||
// to the account.
|
||||
//
|
||||
// To register an anonymous credential:
|
||||
//
|
||||
// 1. Set a backup-id on the authenticated channel via Backups::SetBackupId
|
||||
// 2. Retrieve BackupAuthCredentials via Backups::GetBackupAuthCredentials
|
||||
// 3. Generate a key pair and set the public key via
|
||||
// BackupsAnonymous::SetPublicKey
|
||||
//
|
||||
// Unless otherwise noted, requests for this service require a
|
||||
// SignedPresentation, which includes:
|
||||
//
|
||||
// - a presentation generated from a BackupAuthCredential issued by
|
||||
// GetBackupAuthCredentials
|
||||
// - a signature of that presentation using the private key of a key pair
|
||||
// previously set with SetPublicKey.
|
||||
service BackupsAnonymous {
|
||||
option (require.auth) = AUTH_ONLY_ANONYMOUS;
|
||||
|
||||
// Retrieve credentials used to read objects stored on the backup cdn
|
||||
rpc GetCdnCredentials(GetCdnCredentialsRequest) returns (GetCdnCredentialsResponse) {}
|
||||
|
||||
// Retrieve credentials used to interact with the SecureValueRecoveryB service
|
||||
rpc GetSvrBCredentials(GetSvrBCredentialsRequest) returns (GetSvrBCredentialsResponse) {}
|
||||
|
||||
// Retrieve information about the currently stored message backup
|
||||
rpc GetMessageBackupInfo(GetBackupInfoRequest) returns (GetMessageBackupInfoResponse) {}
|
||||
|
||||
// Retrieve information about the currently stored media backup
|
||||
rpc GetMediaBackupInfo(GetBackupInfoRequest) returns (GetMediaBackupInfoResponse) {}
|
||||
|
||||
// Permanently set the public key of an ED25519 key-pair for the backup-id.
|
||||
// All requests (including this one!) must sign their BackupAuthCredential
|
||||
// presentations with the private key corresponding to the provided public key.
|
||||
rpc SetPublicKey(SetPublicKeyRequest) returns (SetPublicKeyResponse) {}
|
||||
|
||||
// Refresh the backup, indicating that the backup is still active. Clients
|
||||
// must periodically upload new backups or perform a refresh. If a backup has
|
||||
// not been active for 30 days, it may be deleted.
|
||||
rpc Refresh(RefreshRequest) returns (RefreshResponse) {}
|
||||
|
||||
// Retrieve an upload form that can be used to perform a resumable upload
|
||||
rpc GetUploadForm(GetUploadFormRequest) returns (GetUploadFormResponse) {}
|
||||
|
||||
// Copy and re-encrypt media from the attachments cdn into the backup cdn.
|
||||
// The original, already encrypted, attachments will be encrypted with the
|
||||
// provided key material before being copied.
|
||||
//
|
||||
// The copy operation is not atomic and responses will be returned as copy
|
||||
// operations complete with detailed information about the outcome. If an
|
||||
// error is encountered, not all requests may be reflected in the responses.
|
||||
//
|
||||
// On retries, a particular destination media id must not be reused with a
|
||||
// different source media id or different encryption parameters.
|
||||
//
|
||||
// The response stream may be closed with STREAM_CLOSED error reason. In this
|
||||
// case, a BackupStreamClosed message will be present in the error details.
|
||||
rpc CopyMedia(CopyMediaRequest) returns (stream CopyMediaResponse) {}
|
||||
|
||||
// Retrieve a page of media objects stored for this backup-id. A client may
|
||||
// have previously stored media objects that are no longer referenced in their
|
||||
// current backup. To reclaim storage space used by these orphaned objects,
|
||||
// perform a list operation and remove any unreferenced media objects
|
||||
// via DeleteMedia.
|
||||
rpc ListMedia(ListMediaRequest) returns (ListMediaResponse) {}
|
||||
|
||||
// Delete media objects stored with this backup-id. Streams the locations of
|
||||
// media items back when the item has successfully been removed.
|
||||
//
|
||||
// The response stream may be closed with STREAM_CLOSED error reason. In this
|
||||
// case, a BackupStreamClosed message will be present in the error details.
|
||||
rpc DeleteMedia(DeleteMediaRequest) returns (stream DeleteMediaResponse) {}
|
||||
|
||||
// Delete all backup metadata, objects, and stored public key. To use
|
||||
// backups again, a public key must be resupplied.
|
||||
rpc DeleteAll(DeleteAllRequest) returns (DeleteAllResponse) {}
|
||||
}
|
||||
|
||||
message SignedPresentation {
|
||||
// Presentation of a BackupAuthCredential previously retrieved from
|
||||
// GetBackupAuthCredentials on the authenticated channel
|
||||
bytes presentation = 1 [(require.nonEmpty) = true];
|
||||
|
||||
// The presentation signed with the private key corresponding to the public
|
||||
// key set with SetPublicKey
|
||||
bytes presentation_signature = 2 [(require.nonEmpty) = true];
|
||||
}
|
||||
|
||||
message SetPublicKeyRequest {
|
||||
SignedPresentation signed_presentation = 1;
|
||||
|
||||
// The public key, serialized in libsignal's elliptic-curve public key format.
|
||||
bytes public_key = 2 [(require.nonEmpty) = true];
|
||||
}
|
||||
|
||||
message SetPublicKeyResponse {
|
||||
oneof response {
|
||||
// The public key was successfully set
|
||||
google.protobuf.Empty success = 1;
|
||||
|
||||
// The provided backup auth credential presentation could not be
|
||||
// authenticated. Either, the presentation could not be verified, or
|
||||
// the public key signature was invalid, or there is no backup associated
|
||||
// with the backup-id in the presentation.
|
||||
//
|
||||
// This may also be returned if there was an existing public key and the
|
||||
// provided public key did not match.
|
||||
errors.FailedZkAuthentication failed_authentication = 2 [(tag.reason) = "failed_authentication"];
|
||||
}
|
||||
}
|
||||
|
||||
message GetCdnCredentialsRequest {
|
||||
SignedPresentation signed_presentation = 1;
|
||||
uint32 cdn = 2;
|
||||
}
|
||||
message GetCdnCredentialsResponse {
|
||||
message CdnCredentials {
|
||||
map<string, string> headers = 1;
|
||||
}
|
||||
oneof response {
|
||||
// Headers to include with requests to the read from the backup CDN. Includes
|
||||
// time limited read-only credentials.
|
||||
CdnCredentials cdn_credentials = 1;
|
||||
|
||||
// The provided backup auth credential presentation could not be
|
||||
// authenticated. Either, the presentation could not be verified, or
|
||||
// the public key signature was invalid, or there is no backup associated
|
||||
// with the backup-id in the presentation.
|
||||
errors.FailedZkAuthentication failed_authentication = 2 [(tag.reason) = "failed_authentication"];
|
||||
}
|
||||
}
|
||||
|
||||
message GetSvrBCredentialsRequest {
|
||||
SignedPresentation signed_presentation = 1;
|
||||
}
|
||||
|
||||
message GetSvrBCredentialsResponse {
|
||||
message SvrBCredentials {
|
||||
// A username that can be presented to authenticate with SVRB
|
||||
string username = 1;
|
||||
|
||||
// A password that can be presented to authenticate with SVRB
|
||||
string password = 2;
|
||||
}
|
||||
|
||||
oneof response {
|
||||
SvrBCredentials svrb_credentials = 1;
|
||||
|
||||
// The provided backup auth credential presentation could not be
|
||||
// authenticated. Either, the presentation could not be verified, or
|
||||
// the public key signature was invalid, or there is no backup associated
|
||||
// with the backup-id in the presentation.
|
||||
errors.FailedZkAuthentication failed_authentication = 2 [(tag.reason) = "failed_authentication"];
|
||||
}
|
||||
}
|
||||
|
||||
message GetBackupInfoRequest {
|
||||
SignedPresentation signed_presentation = 1;
|
||||
}
|
||||
message GetMessageBackupInfoResponse {
|
||||
message MessageBackupInfo {
|
||||
// The base directory of your backup data on the cdn. Always non-empty, even
|
||||
// if a backup has not actually been stored to the cdn. If a backup was
|
||||
// previously uploaded and has not expired, it can be found in the returned
|
||||
// cdn at /backup_dir/backup_name.
|
||||
string backup_dir = 1;
|
||||
|
||||
// The CDN type where the message backup is stored. Media may be stored
|
||||
// elsewhere.
|
||||
uint32 cdn = 2;
|
||||
|
||||
// The location of the message backup on the cdn. Always non-empty, even
|
||||
// if a backup has not actually been stored to the cdn. If a backup was
|
||||
// previously uploaded and has not expired, it can be found in the returned
|
||||
// cdn at /backup_dir/backup_name.
|
||||
string backup_name = 3;
|
||||
}
|
||||
|
||||
oneof response {
|
||||
MessageBackupInfo backup_info = 1;
|
||||
|
||||
// The provided backup auth credential presentation could not be
|
||||
// authenticated. Either, the presentation could not be verified, or
|
||||
// the public key signature was invalid, or there is no backup associated
|
||||
// with the backup-id in the presentation.
|
||||
errors.FailedZkAuthentication failed_authentication = 2 [(tag.reason) = "failed_authentication"];
|
||||
}
|
||||
}
|
||||
message GetMediaBackupInfoResponse {
|
||||
message MediaBackupInfo {
|
||||
// The base directory of your backup data on the cdn. Always non-empty, even
|
||||
// if no media has been stored to the cdn or the credential is for a tier
|
||||
// that does not support media.
|
||||
string backup_dir = 1;
|
||||
|
||||
// The prefix path component for media objects on a cdn. Stored media for a
|
||||
// media_id can be found at /backup_dir/media_dir/media_id, where the
|
||||
// media_id is encoded in unpadded url-safe base64. Always non-empty, even
|
||||
// if no media has been stored to the cdn or the credential is for a tier
|
||||
// that does not support media.
|
||||
string media_dir = 2;
|
||||
|
||||
// The amount of space used to store media
|
||||
uint64 used_space = 3;
|
||||
}
|
||||
|
||||
oneof response {
|
||||
MediaBackupInfo backup_info = 1;
|
||||
|
||||
// The provided backup auth credential presentation could not be
|
||||
// authenticated. Either, the presentation could not be verified, or
|
||||
// the public key signature was invalid, or there is no backup associated
|
||||
// with the backup-id in the presentation.
|
||||
errors.FailedZkAuthentication failed_authentication = 2 [(tag.reason) = "failed_authentication"];
|
||||
}
|
||||
}
|
||||
|
||||
message RefreshRequest {
|
||||
SignedPresentation signed_presentation = 1;
|
||||
}
|
||||
message RefreshResponse {
|
||||
oneof response {
|
||||
// The backup was successfully refreshed
|
||||
google.protobuf.Empty success = 1;
|
||||
|
||||
// The provided backup auth credential presentation could not be
|
||||
// authenticated. Either, the presentation could not be verified, or
|
||||
// the public key signature was invalid, or there is no backup associated
|
||||
// with the backup-id in the presentation.
|
||||
errors.FailedZkAuthentication failed_authentication = 2 [(tag.reason) = "failed_authentication"];
|
||||
}
|
||||
}
|
||||
|
||||
message GetUploadFormRequest {
|
||||
SignedPresentation signed_presentation = 1;
|
||||
|
||||
message MessagesUploadType {}
|
||||
message MediaUploadType {}
|
||||
oneof upload_type {
|
||||
// Retrieve an upload form that can be used to perform a resumable upload of
|
||||
// a message backup. The finished upload will be available on the backup cdn.
|
||||
MessagesUploadType messages = 2;
|
||||
|
||||
// Retrieve an upload form for a temporary location that can be used to
|
||||
// perform a resumable upload of an attachment. After uploading, the
|
||||
// attachment can be copied into the backup via CopyMedia.
|
||||
//
|
||||
// Behaves identically to the account authenticated version at /attachments.
|
||||
MediaUploadType media = 3;
|
||||
}
|
||||
|
||||
// The length of the attachment for the requested upload form. Uploads
|
||||
// performed with this form will be limited to the provided length.
|
||||
uint64 uploadLength = 4 [(require.range) = {min: 1}];
|
||||
}
|
||||
message GetUploadFormResponse {
|
||||
oneof response {
|
||||
common.UploadForm upload_form = 1;
|
||||
|
||||
// The provided backup auth credential presentation could not be
|
||||
// authenticated. Either, the presentation could not be verified, or
|
||||
// the public key signature was invalid, or there is no backup associated
|
||||
// with the backup-id in the presentation.
|
||||
errors.FailedZkAuthentication failed_authentication = 2 [(tag.reason) = "failed_authentication"];
|
||||
|
||||
// The request size was larger than the maximum supported upload size. The
|
||||
// maximum upload size is subject to change and is governed by
|
||||
// `global.attachments.maxBytes`
|
||||
errors.FailedPrecondition exceeds_max_upload_length = 3 [(tag.reason) = "oversize_upload"];
|
||||
}
|
||||
}
|
||||
|
||||
message CopyMediaItem {
|
||||
// The attachment cdn of the object to copy into the backup
|
||||
uint32 source_attachment_cdn = 1 [(require.range).min = 1, (require.range).max = 3];
|
||||
|
||||
// The attachment key of the object to copy into the backup
|
||||
string source_key = 2 [(require.nonEmpty) = true, (require.base64url) = true];
|
||||
|
||||
// The length of the source attachment before the encryption applied by the
|
||||
// copy operation
|
||||
uint64 object_length = 3;
|
||||
|
||||
// media_id to copy on to the backup CDN
|
||||
bytes media_id = 4 [(require.exactlySize) = 15];
|
||||
|
||||
// A 32-byte key for the MAC
|
||||
bytes hmac_key = 5 [(require.exactlySize) = 32];
|
||||
|
||||
// A 32-byte encryption key for AES
|
||||
bytes encryption_key = 6 [(require.exactlySize) = 32];
|
||||
}
|
||||
|
||||
message CopyMediaRequest {
|
||||
SignedPresentation signed_presentation = 1;
|
||||
|
||||
// Items to copy
|
||||
repeated CopyMediaItem items = 2 [(require.size) = {min: 1, max: 1000}];
|
||||
}
|
||||
|
||||
message CopyMediaResponse {
|
||||
message SourceNotFound {}
|
||||
message WrongSourceLength {}
|
||||
message OutOfSpace {}
|
||||
message CopySuccess {
|
||||
// The backup cdn where this media object is stored
|
||||
uint32 cdn = 1;
|
||||
}
|
||||
|
||||
// The 15-byte media_id from the corresponding CopyMediaItem in the request
|
||||
bytes media_id = 1;
|
||||
|
||||
oneof response {
|
||||
// The media item was successfully copied into the backup
|
||||
CopySuccess success = 2;
|
||||
|
||||
// The source object was not found
|
||||
SourceNotFound source_not_found = 3 [(tag.reason) = "source_not_found"];
|
||||
|
||||
// The provided object length was incorrect
|
||||
WrongSourceLength wrong_source_length = 4 [(tag.reason) = "wrong_source_length"];
|
||||
|
||||
// All media capacity has been consumed. Free some space to continue.
|
||||
OutOfSpace out_of_space = 5 [(tag.reason) = "out_of_space"];
|
||||
}
|
||||
}
|
||||
|
||||
// The reason why a media stream RPC is being prematurely closed by the server.
|
||||
message BackupStreamClosed {
|
||||
oneof reason {
|
||||
// The provided backup auth credential presentation could not be
|
||||
// authenticated. Either, the presentation could not be verified, or
|
||||
// the public key signature was invalid, or there is no backup associated
|
||||
// with the backup-id in the presentation.
|
||||
errors.FailedZkAuthentication failed_authentication = 1 [(tag.reason) = "failed_authentication"];
|
||||
}
|
||||
}
|
||||
|
||||
message ListMediaRequest {
|
||||
SignedPresentation signed_presentation = 1;
|
||||
|
||||
// A cursor returned by a previous call to ListMedia, absent on the first call
|
||||
optional string cursor = 2;
|
||||
|
||||
// If provided, the maximum number of entries to return in a page. If absent,
|
||||
// a server-chosen default is used.
|
||||
optional uint32 limit = 3 [(require.range) = {min: 1, max: 10000}];
|
||||
}
|
||||
|
||||
message ListMediaResponse {
|
||||
message ListEntry {
|
||||
// The backup cdn where this media object is stored
|
||||
uint32 cdn = 1;
|
||||
// The media_id of the object
|
||||
bytes media_id = 2;
|
||||
// The length of the object in bytes
|
||||
uint64 length = 3;
|
||||
}
|
||||
|
||||
message ListResult {
|
||||
|
||||
// A page of media objects stored for this backup ID
|
||||
repeated ListEntry page = 1;
|
||||
|
||||
// The base directory of the backup data on the cdn. The stored media can be
|
||||
// found at /backup_dir/media_dir/media_id, where the media_id is encoded with
|
||||
// unpadded url-safe base64.
|
||||
string backup_dir = 2;
|
||||
|
||||
// The prefix path component for the media objects. The stored media for
|
||||
// media_id can be found at /backup_dir/media_dir/media_id, where the media_id
|
||||
// is encoded with unpadded url-safe base64.
|
||||
string media_dir = 3;
|
||||
|
||||
// If set, the cursor value to pass to the next list request to continue
|
||||
// listing. If absent, all objects have been listed
|
||||
optional string cursor = 4;
|
||||
}
|
||||
|
||||
oneof response {
|
||||
ListResult list_result = 1;
|
||||
|
||||
// The provided backup auth credential presentation could not be
|
||||
// authenticated. Either, the presentation could not be verified, or
|
||||
// the public key signature was invalid, or there is no backup associated
|
||||
// with the backup-id in the presentation.
|
||||
errors.FailedZkAuthentication failed_authentication = 2 [(tag.reason) = "failed_authentication"];
|
||||
}
|
||||
}
|
||||
|
||||
message DeleteAllRequest {
|
||||
SignedPresentation signed_presentation = 1;
|
||||
}
|
||||
message DeleteAllResponse {
|
||||
oneof response {
|
||||
// The backup was successfully scheduled for deletion
|
||||
google.protobuf.Empty success = 1;
|
||||
|
||||
// The provided backup auth credential presentation could not be
|
||||
// authenticated. Either, the presentation could not be verified, or
|
||||
// the public key signature was invalid, or there is no backup associated
|
||||
// with the backup-id in the presentation.
|
||||
errors.FailedZkAuthentication failed_authentication = 2 [(tag.reason) = "failed_authentication"];
|
||||
}
|
||||
}
|
||||
|
||||
message DeleteMediaItem {
|
||||
// The backup cdn where this media object is stored
|
||||
uint32 cdn = 1;
|
||||
|
||||
// The media_id of the object to delete
|
||||
bytes media_id = 2 [(require.exactlySize) = 15];
|
||||
}
|
||||
|
||||
message DeleteMediaRequest {
|
||||
SignedPresentation signed_presentation = 1;
|
||||
|
||||
repeated DeleteMediaItem items = 2 [(require.size) = {min: 1, max: 1000}];
|
||||
}
|
||||
|
||||
message DeleteMediaResponse {
|
||||
DeleteMediaItem deleted_item = 1;
|
||||
}
|
||||
118
pkg/signalmeow/protobuf/org/signal/chat/call_quality.proto
Normal file
118
pkg/signalmeow/protobuf/org/signal/chat/call_quality.proto
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* Copyright 2025 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
option java_multiple_files = true;
|
||||
|
||||
package org.signal.chat.calling.quality;
|
||||
|
||||
import "org/signal/chat/require.proto";
|
||||
|
||||
// Provides methods for submitting call quality surveys
|
||||
service CallQuality {
|
||||
option (require.auth) = AUTH_ONLY_ANONYMOUS;
|
||||
|
||||
// Submits a call quality survey response.
|
||||
rpc SubmitCallQualitySurvey(SubmitCallQualitySurveyRequest) returns (SubmitCallQualitySurveyResponse) {}
|
||||
}
|
||||
|
||||
message SubmitCallQualitySurveyRequest {
|
||||
// Indicates whether the caller was generally satisfied with the quality of
|
||||
// the call
|
||||
bool user_satisfied = 1;
|
||||
|
||||
// A list of call quality issues selected by the caller
|
||||
repeated string call_quality_issues = 2;
|
||||
|
||||
// A free-form description of any additional issues as written by the caller
|
||||
optional string additional_issues_description = 3;
|
||||
|
||||
// A URL for a set of debug logs associated with the call if the caller chose
|
||||
// to submit debug logs
|
||||
optional string debug_log_url = 4;
|
||||
|
||||
// The time at which the call started in milliseconds since the epoch
|
||||
int64 start_timestamp = 5;
|
||||
|
||||
// The time at which the call ended in milliseconds since the epoch
|
||||
int64 end_timestamp = 6;
|
||||
|
||||
// The type of call; note that direct voice calls can become video calls and
|
||||
// vice versa, and this field indicates which mode was selected at call
|
||||
// initiation time. At the time of writing, expected call types are
|
||||
// "direct_voice", "direct_video", "group", and "call_link".
|
||||
string call_type = 7;
|
||||
|
||||
// Indicates whether the call completed without error or if it terminated
|
||||
// abnormally
|
||||
bool success = 8;
|
||||
|
||||
// A client-defined, but human-readable reason for call termination
|
||||
string call_end_reason = 9;
|
||||
|
||||
// The median round-trip time, measured in milliseconds, for STUN/ICE packets
|
||||
// (i.e. connection maintenance and establishment)
|
||||
optional float connection_rtt_median = 10;
|
||||
|
||||
// The median round-trip time, measured in milliseconds, for RTP/RTCP packets
|
||||
// for audio streams
|
||||
optional float audio_rtt_median = 11;
|
||||
|
||||
// The median round-trip time, measured in milliseconds, for RTP/RTCP packets
|
||||
// for video streams
|
||||
optional float video_rtt_median = 12;
|
||||
|
||||
// The median jitter for audio streams, measured in milliseconds, for the
|
||||
// duration of the call as measured by the client submitting the survey
|
||||
optional float audio_recv_jitter_median = 13;
|
||||
|
||||
// The median jitter for video streams, measured in milliseconds, for the
|
||||
// duration of the call as measured by the client submitting the survey
|
||||
optional float video_recv_jitter_median = 14;
|
||||
|
||||
// The median jitter for audio streams, measured in milliseconds, for the
|
||||
// duration of the call as measured by the remote endpoint in the call (either
|
||||
// the peer of the client submitting the survey in a direct call or the SFU in
|
||||
// a group call)
|
||||
optional float audio_send_jitter_median = 15;
|
||||
|
||||
// The median jitter for video streams, measured in milliseconds, for the
|
||||
// duration of the call as measured by the remote endpoint in the call (either
|
||||
// the peer of the client submitting the survey in a direct call or the SFU in
|
||||
// a group call)
|
||||
optional float video_send_jitter_median = 16;
|
||||
|
||||
// The fraction of audio packets lost over the duration of the call as
|
||||
// measured by the client submitting the survey
|
||||
optional float audio_recv_packet_loss_fraction = 17;
|
||||
|
||||
// The fraction of video packets lost over the duration of the call as
|
||||
// measured by the client submitting the survey
|
||||
optional float video_recv_packet_loss_fraction = 18;
|
||||
|
||||
// The fraction of audio packets lost over the duration of the call as
|
||||
// measured by the remote endpoint in the call (either the peer of the client
|
||||
// submitting the survey in a direct call or the SFU in a group call)
|
||||
optional float audio_send_packet_loss_fraction = 19;
|
||||
|
||||
// The fraction of video packets lost over the duration of the call as
|
||||
// measured by the remote endpoint in the call (either the peer of the client
|
||||
// submitting the survey in a direct call or the SFU in a group call)
|
||||
optional float video_send_packet_loss_fraction = 20;
|
||||
|
||||
// Machine-generated telemetry from the call; this is a serialized protobuf
|
||||
// entity generated (and, critically, explained to the user!) by the calling
|
||||
// library
|
||||
optional bytes call_telemetry = 21;
|
||||
|
||||
// A hash of a call ID (shared between clients and never sent to the calling
|
||||
// server) that can be used to correlate survey responses from multiple
|
||||
// participants in a call
|
||||
optional bytes call_id_hash = 22;
|
||||
}
|
||||
|
||||
message SubmitCallQualitySurveyResponse {
|
||||
}
|
||||
64
pkg/signalmeow/protobuf/org/signal/chat/calling.proto
Normal file
64
pkg/signalmeow/protobuf/org/signal/chat/calling.proto
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright 2023 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
option java_multiple_files = true;
|
||||
|
||||
package org.signal.chat.calling;
|
||||
|
||||
import "org/signal/chat/require.proto";
|
||||
|
||||
// Provides methods for getting credentials and relay options for one-on-one
|
||||
// calls.
|
||||
service Calling {
|
||||
option (require.auth) = AUTH_ONLY_AUTHENTICATED;
|
||||
|
||||
// Retrieves TURN credentials and relay options for one-on-one calls.
|
||||
rpc GetCallingRelays(GetCallingRelaysRequest) returns (GetCallingRelaysResponse) {}
|
||||
}
|
||||
|
||||
message GetCallingRelaysRequest {}
|
||||
|
||||
message GetCallingRelaysResponse {
|
||||
message HostnameUrlList {
|
||||
// A collection of hostname-based TURN, TURNS, or STUN URLs a client can use
|
||||
// to connect to a relay.
|
||||
repeated string urls = 1;
|
||||
}
|
||||
|
||||
message IpUrlList {
|
||||
// A collection of IP-based TURN, TURNS, or STUN URLs a client can use to
|
||||
// connect to a relay.
|
||||
repeated string urls = 1;
|
||||
|
||||
// A hostname clients must use to validate the relay's TLS certificate when
|
||||
// connecting via an IP-based TURNS URL. May not be specified if `urls`
|
||||
// contains no TURNS URLs.
|
||||
optional string hostname = 2;
|
||||
}
|
||||
|
||||
message Relay {
|
||||
// A username that can be presented to authenticate with a TURN server.
|
||||
string username = 1;
|
||||
|
||||
// A password that can be presented to authenticate with a TURN server.
|
||||
string password = 2;
|
||||
|
||||
// The duration, in seconds, after which the included username and password
|
||||
// will no longer be valid.
|
||||
uint64 credential_ttl_seconds = 3;
|
||||
|
||||
// A collection of hostname-based URLs clients may use to connect to this
|
||||
// relay.
|
||||
optional HostnameUrlList hostname_urls = 4;
|
||||
|
||||
// A collection of IP-based URLs clients may use to connect to this relay.
|
||||
optional IpUrlList ip_urls = 5;
|
||||
}
|
||||
|
||||
// A collection of calling relays a client may use for one-on-one calls.
|
||||
repeated Relay relays = 1;
|
||||
}
|
||||
52
pkg/signalmeow/protobuf/org/signal/chat/challenge.proto
Normal file
52
pkg/signalmeow/protobuf/org/signal/chat/challenge.proto
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright 2026 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
option java_multiple_files = true;
|
||||
|
||||
package org.signal.chat.challenge;
|
||||
|
||||
import "org/signal/chat/require.proto";
|
||||
|
||||
service Challenge {
|
||||
option (require.auth) = AUTH_ONLY_AUTHENTICATED;
|
||||
// Submit proof of a challenge completion
|
||||
|
||||
// Some server endpoints (the "send message" endpoint, for example) may return
|
||||
// a response indicating the client must complete a challenge before continuing.
|
||||
// Clients may use this endpoint to provide proof of a completed challenge.
|
||||
// If successful, the client may then continue their original operation.
|
||||
rpc HandleChallengeResponse(AnswerChallengeRequest) returns (AnswerChallengeResponse) {}
|
||||
}
|
||||
|
||||
message AnswerChallengeRequest {
|
||||
|
||||
message AnswerPushChallengeRequest {
|
||||
// The challenge string provided to the client via a push payload
|
||||
string challenge = 1 [(require.nonEmpty) = true];
|
||||
}
|
||||
|
||||
message AnswerCaptchaChallengeRequest {
|
||||
// A string representing a solved captcha
|
||||
// Example: signal-hcaptcha.30b01b46-d8c9-4c30-bbd7-9719acfe0c10.challenge.abcdefg1345
|
||||
string captcha = 1 [(require.nonEmpty) = true];
|
||||
}
|
||||
|
||||
// The opaque token id from the ChallengeRequired response returned by the
|
||||
// server endpoint that requested the challenge
|
||||
string token = 1 [(require.nonEmpty) = true];
|
||||
|
||||
oneof request {
|
||||
AnswerPushChallengeRequest push = 2;
|
||||
AnswerCaptchaChallengeRequest captcha = 3;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
message AnswerChallengeResponse {
|
||||
// Whether the challenge proof was accepted
|
||||
bool success = 1;
|
||||
}
|
||||
176
pkg/signalmeow/protobuf/org/signal/chat/common.proto
Normal file
176
pkg/signalmeow/protobuf/org/signal/chat/common.proto
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
/*
|
||||
* Copyright 2023 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
option java_multiple_files = true;
|
||||
|
||||
package org.signal.chat.common;
|
||||
|
||||
import "org/signal/chat/require.proto";
|
||||
|
||||
enum IdentityType {
|
||||
IDENTITY_TYPE_UNSPECIFIED = 0;
|
||||
IDENTITY_TYPE_ACI = 1;
|
||||
IDENTITY_TYPE_PNI = 2;
|
||||
}
|
||||
|
||||
message ServiceIdentifier {
|
||||
// The type of identity represented by this service identifier.
|
||||
IdentityType identity_type = 1 [(require.specified) = true];
|
||||
|
||||
// The UUID of the identity represented by this service identifier.
|
||||
bytes uuid = 2 [(require.exactlySize) = 16];
|
||||
}
|
||||
|
||||
// All identifiers associated with an account.
|
||||
message AccountIdentifiers {
|
||||
// A list of service identifiers for the identified account. Always includes
|
||||
// exactly one ACI service identifier and at most one PNI service identifier.
|
||||
repeated ServiceIdentifier service_identifiers = 1;
|
||||
|
||||
// The phone number associated with the identified account. May be empty if
|
||||
// the given account does not have a phone number.
|
||||
string e164 = 2 [(org.signal.chat.require.e164) = true];
|
||||
|
||||
// The username hash (if any) associated with the identified account. May be
|
||||
// empty if no username is associated with the identified account.
|
||||
bytes username_hash = 3 [(org.signal.chat.require.exactlySize) = 0, (org.signal.chat.require.exactlySize) = 32];
|
||||
|
||||
// The username link handle UUID associated with the identified account.
|
||||
// May be empty if no username is associated with the identified account.
|
||||
bytes username_link_handle = 4 [(org.signal.chat.require.exactlySize) = 0, (org.signal.chat.require.exactlySize) = 16];
|
||||
}
|
||||
|
||||
message EcPreKey {
|
||||
// A locally-unique identifier for this key, which will be provided by
|
||||
// peers using this key to encrypt messages so the private key can be looked
|
||||
// up.
|
||||
int32 key_id = 1 [(require.range).min = 0];
|
||||
|
||||
// The public key, serialized in libsignal's elliptic-curve public key format.
|
||||
bytes public_key = 2 [(require.nonEmpty) = true];
|
||||
}
|
||||
|
||||
message EcSignedPreKey {
|
||||
// A locally-unique identifier for this key, which will be provided by
|
||||
// peers using this key to encrypt messages so the private key can be looked
|
||||
// up.
|
||||
int32 key_id = 1 [(require.range).min = 0];
|
||||
|
||||
// The public key, serialized in libsignal's elliptic-curve public key format.
|
||||
bytes public_key = 2 [(require.nonEmpty) = true];
|
||||
|
||||
// A signature of the public key, verifiable with the identity key for the
|
||||
// account/identity associated with this pre-key.
|
||||
bytes signature = 3 [(require.nonEmpty) = true];
|
||||
}
|
||||
|
||||
message KemSignedPreKey {
|
||||
// An locally-unique identifier for this key, which will be provided by peers
|
||||
// using this key to encrypt messages so the private key can be looked up.
|
||||
int32 key_id = 1 [(require.range).min = 0];
|
||||
|
||||
// The public key, serialized in libsignal's Kyber1024 public key format.
|
||||
bytes public_key = 2 [(require.nonEmpty) = true];
|
||||
|
||||
// A signature of the public key, verifiable with the identity key for the
|
||||
// account/identity associated with this pre-key.
|
||||
bytes signature = 3 [(require.nonEmpty) = true];
|
||||
}
|
||||
|
||||
enum DeviceCapability {
|
||||
DEVICE_CAPABILITY_UNSPECIFIED = 0;
|
||||
DEVICE_CAPABILITY_STORAGE = 1;
|
||||
DEVICE_CAPABILITY_TRANSFER = 2;
|
||||
reserved 3;
|
||||
reserved 4;
|
||||
reserved 5;
|
||||
DEVICE_CAPABILITY_ATTACHMENT_BACKFILL = 6;
|
||||
DEVICE_CAPABILITY_SPARSE_POST_QUANTUM_RATCHET = 7;
|
||||
DEVICE_CAPABILITY_PROFILES_V2 = 8;
|
||||
DEVICE_CAPABILITY_USERNAME_CHANGE_SYNC_MESSAGE = 9;
|
||||
DEVICE_CAPABILITY_OPTIONAL_PHONE_NUMBER = 10;
|
||||
}
|
||||
|
||||
message ZkCredential {
|
||||
/*
|
||||
* Day on which this credential can be redeemed, in UTC seconds since epoch
|
||||
*/
|
||||
int64 redemption_time = 1;
|
||||
|
||||
/*
|
||||
* The ZK credential, using libsignal's serialization
|
||||
*/
|
||||
bytes credential = 2 [(require.nonEmpty) = true];
|
||||
}
|
||||
|
||||
// An upload location and credentials which may be used to upload an object
|
||||
// to an external CDN
|
||||
message UploadForm {
|
||||
// Indicates the CDN type. 3 indicates resumable uploads using TUS
|
||||
uint32 cdn = 1;
|
||||
|
||||
// The location within the specified cdn where the finished upload can be found
|
||||
string key = 2;
|
||||
|
||||
// A map of headers to include with all upload requests. Potentially contains
|
||||
// time-limited upload credentials
|
||||
map<string, string> headers = 3;
|
||||
|
||||
// The URL to upload to with the appropriate protocol
|
||||
string signed_upload_location = 4;
|
||||
}
|
||||
|
||||
// An upload location, credentials, and metadata which may be used to upload an
|
||||
// object to AWS S3
|
||||
message S3UploadForm {
|
||||
// The S3 key (i.e. path and filename) for the uploaded file.
|
||||
string key = 1;
|
||||
|
||||
// A scoped credential. Includes the AWS access key, date, region targeted,
|
||||
// and AWS service.
|
||||
string credential = 2;
|
||||
|
||||
// The type of access control for the uploaded file.
|
||||
string acl = 3;
|
||||
|
||||
// The algorithm used to calculate a signature on the S3 policy.
|
||||
string algorithm = 4;
|
||||
|
||||
// The timestamp (formatted as "yyyyMMdd'T'HHmmssX") at which the S3 policy
|
||||
// and signature were generated.
|
||||
string date = 5;
|
||||
|
||||
// The S3 policy (as a base64-encoded JSON string) used to upload the file.
|
||||
string policy = 6;
|
||||
|
||||
// A digital signature (formatted as a hex string) on the S3 policy.
|
||||
string signature = 7;
|
||||
}
|
||||
|
||||
message BadgeSvg {
|
||||
// File name of the scalable vector graphic for light mode.
|
||||
string light = 1;
|
||||
// File name of the scalable vector graphic for dark mode.
|
||||
string dark = 2;
|
||||
}
|
||||
|
||||
message Badge {
|
||||
// An ID that uniquely identifies the badge.
|
||||
string id = 1;
|
||||
// The category the badge falls in ("donor" or "other").
|
||||
string category = 2;
|
||||
// The badge name.
|
||||
string name = 3;
|
||||
// The badge description.
|
||||
string description = 4;
|
||||
// Different size badge SVG files.
|
||||
repeated string sprites6 = 5;
|
||||
// File name of the scalable vector graphic representing this badge.
|
||||
string svg = 6;
|
||||
// Pairs of light/dark SVG files designed for display at different sizes.
|
||||
repeated BadgeSvg svgs = 7;
|
||||
}
|
||||
166
pkg/signalmeow/protobuf/org/signal/chat/credentials.proto
Normal file
166
pkg/signalmeow/protobuf/org/signal/chat/credentials.proto
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
/*
|
||||
* Copyright 2023 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
option java_multiple_files = true;
|
||||
|
||||
import "org/signal/chat/require.proto";
|
||||
|
||||
package org.signal.chat.credentials;
|
||||
|
||||
// Provides methods for obtaining and verifying credentials that allow an
|
||||
// authenticated user to authenticate in another service or context without
|
||||
// revealing their identity.
|
||||
service Credentials {
|
||||
option (require.auth) = AUTH_ONLY_AUTHENTICATED;
|
||||
|
||||
// Generates and returns an external service credentials for the caller.
|
||||
rpc GetExternalServiceCredentials(GetExternalServiceCredentialsRequest)
|
||||
returns (GetExternalServiceCredentialsResponse) {}
|
||||
|
||||
// Generates a pair of delivery certificates that the holder can include to
|
||||
// identify themselves to a message recipient (but not the server) in a
|
||||
// sealed-sender message.
|
||||
rpc GetDeliveryCertificate(GetDeliveryCertificateRequest)
|
||||
returns (GetDeliveryCertificateResponse) {}
|
||||
|
||||
// Generates a set of zero-knowledge credentials for various group-related
|
||||
// actions.
|
||||
rpc GetGroupCredentials(GetGroupCredentialsRequest)
|
||||
returns (GetGroupCredentialsResponse) {}
|
||||
|
||||
// Generates zero-knowledge credentials for creating call links.
|
||||
rpc GetCreateCallLinkCredentials(GetCreateCallLinkCredentialsRequest)
|
||||
returns (GetCreateCallLinkCredentialsResponse) {}
|
||||
}
|
||||
|
||||
// Provides methods for working with previously-generated credentials without
|
||||
// revealing an association between the credentials and the caller's identity to
|
||||
// the server.
|
||||
service CredentialsAnonymous {
|
||||
option (require.auth) = AUTH_ONLY_ANONYMOUS;
|
||||
|
||||
// Given a list of secure value recovery (SVR) service credentials and a phone
|
||||
// number, checks and returns which of the provided credentials were generated
|
||||
// by the user with the given phone number and have not yet expired.
|
||||
rpc CheckSvrCredentials(CheckSvrCredentialsRequest)
|
||||
returns (CheckSvrCredentialsResponse) {}
|
||||
}
|
||||
|
||||
enum ExternalServiceType {
|
||||
EXTERNAL_SERVICE_TYPE_UNSPECIFIED = 0;
|
||||
EXTERNAL_SERVICE_TYPE_DIRECTORY = 1;
|
||||
EXTERNAL_SERVICE_TYPE_PAYMENTS = 2;
|
||||
EXTERNAL_SERVICE_TYPE_STORAGE = 3;
|
||||
EXTERNAL_SERVICE_TYPE_SVR = 4;
|
||||
}
|
||||
|
||||
message GetExternalServiceCredentialsRequest {
|
||||
// A service to request credentials for.
|
||||
ExternalServiceType externalService = 1;
|
||||
}
|
||||
|
||||
message GetExternalServiceCredentialsResponse {
|
||||
// A username that can be presented to authenticate with the external service.
|
||||
string username = 1;
|
||||
|
||||
// A password that can be presented to authenticate with the external service.
|
||||
string password = 2;
|
||||
}
|
||||
|
||||
enum AuthCheckResult {
|
||||
AUTH_CHECK_RESULT_UNSPECIFIED = 0;
|
||||
// The credentials could be used to make a call to SVR service by the user
|
||||
// associated with the `CheckSvrCredentialsRequest.number` phone number.
|
||||
AUTH_CHECK_RESULT_MATCH = 1;
|
||||
// The credentials were generated by a different user.
|
||||
AUTH_CHECK_RESULT_NO_MATCH = 2;
|
||||
// This status indicates that the corresponding credentials token should no longer be used.
|
||||
// This may be because it has expired or invalid, but it can also mean that there is a more
|
||||
// recent token in the request which should be used instead.
|
||||
AUTH_CHECK_RESULT_INVALID = 3;
|
||||
}
|
||||
|
||||
message CheckSvrCredentialsRequest {
|
||||
// A phone number in the E164 format to check the passwords against.
|
||||
// Only passwords generated for the user associated with the given number will be marked as `AUTH_CHECK_RESULT_MATCH`.
|
||||
string number = 1;
|
||||
|
||||
// A list of credentials from previously made calls to `ExternalServiceCredentials.GetExternalServiceCredentials()`
|
||||
// for `EXTERNAL_SERVICE_TYPE_SVR`. This list may contain credentials generated by different users. Up to 10 credentials
|
||||
// can be checked.
|
||||
repeated string passwords = 2 [(require.nonEmpty) = true, (require.size) = {max: 10}];
|
||||
}
|
||||
|
||||
// For each of the credentials tokens in the `CheckSvrCredentialsRequest` contains the result of the check.
|
||||
message CheckSvrCredentialsResponse {
|
||||
|
||||
map<string, AuthCheckResult> matches = 1;
|
||||
}
|
||||
|
||||
message GetDeliveryCertificateRequest {
|
||||
}
|
||||
|
||||
// A pair of message delivery certificates. The response unconditionally
|
||||
// includes certificates with and without the caller's phone number so the
|
||||
// server never learns anything about the caller's intent to share their phone
|
||||
// number with their contacts.
|
||||
message GetDeliveryCertificateResponse {
|
||||
// A delivery receipt that includes the caller's phone number; may be empty if
|
||||
// the authenticated account does not have a phone number
|
||||
bytes certificate_with_e164 = 1;
|
||||
|
||||
// A delivery receipt that does not include the caller's phone number
|
||||
bytes certificate_without_e164 = 2;
|
||||
}
|
||||
|
||||
message GetGroupCredentialsRequest {
|
||||
// The earliest time for which to issue group credentials; must be aligned to
|
||||
// a UTC day boundary and may be no more than one day in the past at the time
|
||||
// of the call.
|
||||
uint64 redemption_start_seconds = 1;
|
||||
|
||||
// The latest time for which to issue group credentials; must be aligned to a
|
||||
// UTC day boundary and no more than seven days in the future at the time of
|
||||
// the call.
|
||||
uint64 redemption_end_seconds = 2;
|
||||
}
|
||||
|
||||
message GetGroupCredentialsResponse {
|
||||
// A zero-knowledge credential that may be redeemed at or up to one day after
|
||||
// the given redemption time
|
||||
message CredentialAndRedemptionTime {
|
||||
bytes credential = 1;
|
||||
uint64 redemption_time_seconds = 2;
|
||||
}
|
||||
|
||||
// A collection of credentials allowing the holder to anonymously
|
||||
// authenticate themselves for group-related actions
|
||||
repeated CredentialAndRedemptionTime group_credentials = 1;
|
||||
|
||||
// A collection of credentials allowing the holder to read, update, and delete
|
||||
// group call links
|
||||
repeated CredentialAndRedemptionTime call_link_auth_credentials = 2;
|
||||
|
||||
// The phone number identifier for which the included credentials were
|
||||
// generated. Empty if the account does not have a phone number.
|
||||
bytes pni = 3;
|
||||
}
|
||||
|
||||
message GetCreateCallLinkCredentialsRequest {
|
||||
// A zero-knowledge credential request
|
||||
bytes credential_request = 1;
|
||||
}
|
||||
|
||||
message GetCreateCallLinkCredentialsResponse {
|
||||
// A zero-knowledge credential that may be redeemed at or up to one day after
|
||||
// the given redemption time
|
||||
bytes credential = 1;
|
||||
|
||||
// The earliest time, in seconds since the epoch, at which the associated
|
||||
// credential may be redeemed
|
||||
uint64 redemption_time_seconds = 2;
|
||||
}
|
||||
138
pkg/signalmeow/protobuf/org/signal/chat/device.proto
Normal file
138
pkg/signalmeow/protobuf/org/signal/chat/device.proto
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* Copyright 2023 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
option java_multiple_files = true;
|
||||
|
||||
package org.signal.chat.device;
|
||||
|
||||
import "google/protobuf/empty.proto";
|
||||
|
||||
import "org/signal/chat/common.proto";
|
||||
import "org/signal/chat/errors.proto";
|
||||
import "org/signal/chat/require.proto";
|
||||
import "org/signal/chat/tag.proto";
|
||||
|
||||
// Provides methods for working with devices attached to a Signal account.
|
||||
service Devices {
|
||||
option (require.auth) = AUTH_ONLY_AUTHENTICATED;
|
||||
|
||||
// Returns a list of devices associated with the caller's account.
|
||||
rpc GetDevices(GetDevicesRequest) returns (GetDevicesResponse) {}
|
||||
|
||||
// Removes a linked device from the caller's account.
|
||||
//
|
||||
// Linked devices may only remove themselves. Primary devices may remove
|
||||
// any device other than themselves.
|
||||
rpc RemoveDevice(RemoveDeviceRequest) returns (RemoveDeviceResponse) {}
|
||||
|
||||
// Sets the encrypted human-readable name for a specific devices. Primary
|
||||
// devices may change the name of any device associated with their account,
|
||||
// but linked devices may only change their own name. The response will
|
||||
// indicate if the target device was not found.
|
||||
rpc SetDeviceName(SetDeviceNameRequest) returns (SetDeviceNameResponse) {}
|
||||
|
||||
// Sets the token(s) the server should use to send new message notifications
|
||||
// to the authenticated device.
|
||||
rpc SetPushToken(SetPushTokenRequest) returns (SetPushTokenResponse) {}
|
||||
|
||||
// Removes any push tokens associated with the authenticated device. After
|
||||
// calling this method, the server will assume that the authenticated device
|
||||
// will periodically poll for new messages.
|
||||
rpc ClearPushToken(ClearPushTokenRequest) returns (ClearPushTokenResponse) {}
|
||||
|
||||
// Declares that the authenticated device supports certain features.
|
||||
rpc SetCapabilities(SetCapabilitiesRequest) returns (SetCapabilitiesResponse) {}
|
||||
}
|
||||
|
||||
message GetDevicesRequest {}
|
||||
|
||||
message GetDevicesResponse {
|
||||
message LinkedDevice {
|
||||
// The identifier for the device within an account.
|
||||
uint32 id = 1;
|
||||
|
||||
// A sequence of bytes that encodes an encrypted human-readable name for
|
||||
// this device.
|
||||
bytes name = 2;
|
||||
|
||||
// The approximate time, in milliseconds since the epoch, at which this
|
||||
// device last connected to the server.
|
||||
uint64 last_seen = 3;
|
||||
|
||||
// The registration ID of the given device.
|
||||
uint32 registration_id = 4 [(require.range).max = 0x3fff];
|
||||
|
||||
// A sequence of bytes that encodes the time,
|
||||
// in milliseconds since the epoch, at which this device was
|
||||
// attached to its parent account.
|
||||
bytes created_at_ciphertext = 5;
|
||||
}
|
||||
|
||||
// A list of devices linked to the authenticated account.
|
||||
repeated LinkedDevice devices = 1;
|
||||
}
|
||||
|
||||
message RemoveDeviceRequest {
|
||||
// The identifier for the device to remove from the authenticated account. The
|
||||
// identifier must not be for the primary device.
|
||||
uint32 id = 1;
|
||||
}
|
||||
|
||||
message SetDeviceNameRequest {
|
||||
// A sequence of bytes that encodes an encrypted human-readable name for this
|
||||
// device.
|
||||
bytes name = 1 [(require.size) = {min: 1, max: 225}];
|
||||
|
||||
// The identifier for the device for which to set a name.
|
||||
uint32 id = 2;
|
||||
}
|
||||
|
||||
message SetDeviceNameResponse {
|
||||
oneof response {
|
||||
// The device name was successfully set
|
||||
google.protobuf.Empty success = 1;
|
||||
|
||||
// No device with the provided identifier was found on the account
|
||||
errors.NotFound target_device_not_found = 2 [(tag.reason) = "not_found"];
|
||||
}
|
||||
}
|
||||
|
||||
message RemoveDeviceResponse {}
|
||||
|
||||
message SetPushTokenRequest {
|
||||
message ApnsTokenRequest {
|
||||
// A "standard" APNs device token.
|
||||
string apns_token = 1 [(require.nonEmpty) = true];
|
||||
}
|
||||
|
||||
message FcmTokenRequest {
|
||||
// An FCM push token.
|
||||
string fcm_token = 1 [(require.nonEmpty) = true];
|
||||
}
|
||||
|
||||
oneof token_request {
|
||||
// If present, specifies the APNs device token(s) the server will use to
|
||||
// send new message notifications to the authenticated device.
|
||||
ApnsTokenRequest apns_token_request = 1;
|
||||
|
||||
// If present, specifies the FCM push token the server will use to send new
|
||||
// message notifications to the authenticated device.
|
||||
FcmTokenRequest fcm_token_request = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message SetPushTokenResponse {}
|
||||
|
||||
message ClearPushTokenRequest {}
|
||||
|
||||
message ClearPushTokenResponse {}
|
||||
|
||||
message SetCapabilitiesRequest {
|
||||
repeated common.DeviceCapability capabilities = 1;
|
||||
}
|
||||
|
||||
message SetCapabilitiesResponse {}
|
||||
59
pkg/signalmeow/protobuf/org/signal/chat/donations.proto
Normal file
59
pkg/signalmeow/protobuf/org/signal/chat/donations.proto
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright 2026 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
option java_multiple_files = true;
|
||||
|
||||
package org.signal.chat.donations;
|
||||
|
||||
import "google/protobuf/empty.proto";
|
||||
import "org/signal/chat/require.proto";
|
||||
import "org/signal/chat/errors.proto";
|
||||
import "org/signal/chat/tag.proto";
|
||||
|
||||
service Donations {
|
||||
option (require.auth) = AUTH_ONLY_AUTHENTICATED;
|
||||
// Redeem a receipt acquired from Subscriptions.CreateSubscriptionReceiptCredentials
|
||||
// to add a badge to the account. After successful redemption, profile
|
||||
// responses will include the corresponding badge (if configured as visible)
|
||||
// until the expiration time on the receipt.
|
||||
rpc RedeemReceipt(RedeemReceiptRequest) returns (RedeemReceiptResponse) {}
|
||||
|
||||
// Generate a set of anonymous, single-use, permits for use with /v1/subscription endpoints.
|
||||
//
|
||||
// If rate limited, reduce requested permit count and/or try again after the prescribed delay.
|
||||
rpc CreateDonationPermit(CreateDonationPermitRequest) returns (CreateDonationPermitResponse) {}
|
||||
}
|
||||
|
||||
message RedeemReceiptRequest {
|
||||
// Presentation of the ZK receipt acquired when the subscription was created
|
||||
bytes receiptCredentialPresentation = 1 [(require.exactlySize) = 329];
|
||||
// If true, the corresponding badge should be visible on the profile
|
||||
bool visible = 2;
|
||||
// If true, and the new badge is visible, it should be the primary badge on the profile
|
||||
bool primary = 3;
|
||||
}
|
||||
|
||||
message RedeemReceiptResponse {
|
||||
oneof response {
|
||||
// The receipt was successfully redeemed
|
||||
google.protobuf.Empty success = 1;
|
||||
// The provided presentation is invalid
|
||||
errors.FailedZkAuthentication failed_authentication = 2 [(tag.reason) = "failed_authentication"];
|
||||
// The receipt was already redeemed for a different account
|
||||
errors.FailedPrecondition already_redeemed = 3 [(tag.reason) = "already_redeemed"];
|
||||
}
|
||||
}
|
||||
|
||||
message CreateDonationPermitRequest {
|
||||
// a serialized libsignal DonationPermitRequest
|
||||
bytes donation_permit_request = 1 [(require.nonEmpty) = true];
|
||||
}
|
||||
|
||||
message CreateDonationPermitResponse {
|
||||
// a serialized libsignal DonationPermitResponse
|
||||
bytes donation_permit_response = 1;
|
||||
}
|
||||
34
pkg/signalmeow/protobuf/org/signal/chat/errors.proto
Normal file
34
pkg/signalmeow/protobuf/org/signal/chat/errors.proto
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright 2025 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
option java_multiple_files = true;
|
||||
|
||||
package org.signal.chat.errors;
|
||||
|
||||
// Response message that indicates a particular resource was not found.
|
||||
message NotFound {}
|
||||
|
||||
// Response message that indicates that some precondition of the request was not
|
||||
// met. For example, if there was a request to update foo, but foo had not been
|
||||
// set, this would be an appropriate error.
|
||||
message FailedPrecondition {
|
||||
// An optional description indicating what precondition failed.
|
||||
string description = 1;
|
||||
}
|
||||
|
||||
// Response message that authentication via an anonymous credential failed.
|
||||
message FailedZkAuthentication {
|
||||
// An optional description with additional information about the failure.
|
||||
string description = 1;
|
||||
}
|
||||
|
||||
// Response message that indicates authorization to perform an unidentified
|
||||
// operation via an endorsement or access key failed
|
||||
message FailedUnidentifiedAuthorization {
|
||||
// An optional description with additional information about the failure.
|
||||
string description = 1;
|
||||
}
|
||||
236
pkg/signalmeow/protobuf/org/signal/chat/keys.proto
Normal file
236
pkg/signalmeow/protobuf/org/signal/chat/keys.proto
Normal file
|
|
@ -0,0 +1,236 @@
|
|||
/*
|
||||
* Copyright 2023 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
option java_multiple_files = true;
|
||||
|
||||
package org.signal.chat.keys;
|
||||
|
||||
import "google/protobuf/empty.proto";
|
||||
|
||||
import "org/signal/chat/common.proto";
|
||||
import "org/signal/chat/errors.proto";
|
||||
import "org/signal/chat/require.proto";
|
||||
import "org/signal/chat/tag.proto";
|
||||
|
||||
// Provides methods for working with pre-keys.
|
||||
service Keys {
|
||||
option (require.auth) = AUTH_ONLY_AUTHENTICATED;
|
||||
|
||||
// Retrieves an approximate count of the number of the various kinds of
|
||||
// pre-keys stored for the authenticated device.
|
||||
rpc GetPreKeyCount (GetPreKeyCountRequest) returns (GetPreKeyCountResponse) {}
|
||||
|
||||
// Retrieves a set of pre-keys for establishing a session with the targeted
|
||||
// device or devices. Note that callers with an unidentified access key for
|
||||
// the targeted account should use the version of this method in
|
||||
// `KeysAnonymous` instead.
|
||||
rpc GetPreKeys(GetPreKeysRequest) returns (GetPreKeysResponse) {}
|
||||
|
||||
// Uploads a new set of one-time EC pre-keys for the authenticated device,
|
||||
// clearing any previously-stored pre-keys. Note that all keys submitted via
|
||||
// a single call to this method _must_ have the same identity type (i.e. if
|
||||
// the first key has an ACI identity type, then all other keys in the same
|
||||
// stream must also have an ACI identity type). The provided list of pre-keys
|
||||
// must be non-empty.
|
||||
rpc SetOneTimeEcPreKeys (SetOneTimeEcPreKeysRequest) returns (SetPreKeyResponse) {}
|
||||
|
||||
// Uploads a new set of one-time KEM pre-keys for the authenticated device,
|
||||
// clearing any previously-stored pre-keys. Note that all keys submitted via
|
||||
// a single call to this method _must_ have the same identity type (i.e. if
|
||||
// the first key has an ACI identity type, then all other keys in the same
|
||||
// stream must also have an ACI identity type). The provided list of pre-keys
|
||||
// must be non-empty.
|
||||
rpc SetOneTimeKemSignedPreKeys (SetOneTimeKemSignedPreKeysRequest) returns (SetPreKeyResponse) {}
|
||||
|
||||
// Sets the signed EC pre-key for one identity (i.e. ACI or PNI) associated
|
||||
// with the authenticated device.
|
||||
rpc SetEcSignedPreKey (SetEcSignedPreKeyRequest) returns (SetPreKeyResponse) {}
|
||||
|
||||
// Sets the last-resort KEM pre-key for one identity (i.e. ACI or PNI)
|
||||
// associated with the authenticated device.
|
||||
rpc SetKemLastResortPreKey (SetKemLastResortPreKeyRequest) returns (SetPreKeyResponse) {}
|
||||
}
|
||||
|
||||
// Provides methods for working with pre-keys using "unidentified access"
|
||||
// credentials.
|
||||
service KeysAnonymous {
|
||||
option (require.auth) = AUTH_ONLY_ANONYMOUS;
|
||||
|
||||
// Retrieves a set of pre-keys for establishing a session with the targeted
|
||||
// device or devices. Callers must not submit any self-identifying credentials
|
||||
// when calling this method and must instead present the targeted account's
|
||||
// unidentified access key as an anonymous authentication mechanism. Callers
|
||||
// without an unidentified access key should use the equivalent, authenticated
|
||||
// method in `Keys` instead.
|
||||
rpc GetPreKeys(GetPreKeysAnonymousRequest) returns (GetPreKeysAnonymousResponse) {}
|
||||
|
||||
// Checks identity key fingerprints of the target accounts.
|
||||
//
|
||||
// Returns a stream of elements, each one representing an account that had a mismatched
|
||||
// identity key fingerprint with the server and the corresponding identity key stored by the server.
|
||||
rpc CheckIdentityKeys(stream CheckIdentityKeyRequest) returns (stream CheckIdentityKeyResponse) {}
|
||||
}
|
||||
|
||||
message GetPreKeyCountRequest {
|
||||
}
|
||||
|
||||
message GetPreKeyCountResponse {
|
||||
// The approximate number of one-time EC pre-keys stored for the
|
||||
// authenticated device and associated with the caller's ACI.
|
||||
uint32 aci_ec_pre_key_count = 1;
|
||||
|
||||
// The approximate number of one-time Kyber pre-keys stored for the
|
||||
// authenticated device and associated with the caller's ACI.
|
||||
uint32 aci_kem_pre_key_count = 2;
|
||||
|
||||
// The approximate number of one-time EC pre-keys stored for the
|
||||
// authenticated device and associated with the caller's PNI. 0 if
|
||||
// the account does not possess a phone number.
|
||||
uint32 pni_ec_pre_key_count = 3;
|
||||
|
||||
// The approximate number of one-time KEM pre-keys stored for the
|
||||
// authenticated device and associated with the caller's PNI. 0 if
|
||||
// the account does not possess a phone number.
|
||||
uint32 pni_kem_pre_key_count = 4;
|
||||
}
|
||||
|
||||
message GetPreKeysRequest {
|
||||
// The service identifier of the account for which to retrieve pre-keys.
|
||||
common.ServiceIdentifier target_identifier = 1;
|
||||
|
||||
// The ID of the device associated with the targeted account for which to
|
||||
// retrieve pre-keys. If not set, pre-keys are returned for all devices
|
||||
// associated with the targeted account.
|
||||
optional uint32 device_id = 2;
|
||||
}
|
||||
|
||||
message GetPreKeysAnonymousRequest {
|
||||
// The request to retrieve pre-keys for a specific account/device(s).
|
||||
GetPreKeysRequest request = 1;
|
||||
|
||||
// A means to authorize the request.
|
||||
oneof authorization {
|
||||
// The unidentified access key (UAK) for the targeted account.
|
||||
bytes unidentified_access_key = 2;
|
||||
|
||||
// A group send endorsement token for the targeted account.
|
||||
bytes group_send_token = 3;
|
||||
|
||||
// The destination account allows unrestricted unidentified access
|
||||
google.protobuf.Empty unrestricted_access = 4;
|
||||
}
|
||||
}
|
||||
|
||||
message DevicePreKeyBundle {
|
||||
// The EC signed pre-key associated with the targeted
|
||||
// account/device/identity.
|
||||
common.EcSignedPreKey ec_signed_pre_key = 1;
|
||||
|
||||
// A one-time EC pre-key for the targeted account/device/identity. May not
|
||||
// be set if no one-time EC pre-keys are available.
|
||||
common.EcPreKey ec_one_time_pre_key = 2;
|
||||
|
||||
// A one-time KEM pre-key (or a last-resort KEM pre-key) for the targeted
|
||||
// account/device/identity.
|
||||
common.KemSignedPreKey kem_one_time_pre_key = 3;
|
||||
|
||||
// The registration ID for the targeted account/device/identity.
|
||||
uint32 registration_id = 4;
|
||||
}
|
||||
|
||||
message AccountPreKeyBundles {
|
||||
// The identity key associated with the targeted account/identity.
|
||||
bytes identity_key = 1;
|
||||
|
||||
// A map of device IDs to pre-key "bundles" for the targeted account.
|
||||
map<uint32, DevicePreKeyBundle> device_pre_keys = 2;
|
||||
|
||||
// Whether the account has enabled sealed sender from anyone. Always false
|
||||
// if the request was for a PNI, which does not allow any unidentified access.
|
||||
bool unrestricted_unidentified_access = 3;
|
||||
|
||||
// If the target supports unidentified access and has an unidentified access
|
||||
// key, a fingerprint of the target's UAK. This may be used to detect a change
|
||||
// in the UAK that the sender has for the target before actually sending a message. Otherwise, empty.
|
||||
bytes unidentified_access_key_fingerprint = 4;
|
||||
}
|
||||
|
||||
message GetPreKeysResponse {
|
||||
oneof response {
|
||||
// The requested pre-key bundles
|
||||
AccountPreKeyBundles pre_keys = 1;
|
||||
|
||||
// Either the target account was not found, no active device with the given
|
||||
// ID (if specified) was found on the target account.
|
||||
errors.NotFound target_not_found = 2 [(tag.reason) = "not_found"];
|
||||
}
|
||||
}
|
||||
|
||||
message GetPreKeysAnonymousResponse {
|
||||
oneof response {
|
||||
// The requested pre-key bundles
|
||||
AccountPreKeyBundles pre_keys = 1;
|
||||
|
||||
// Either the target account was not found, no active device with the given
|
||||
// ID (if specified) was found on the target account.
|
||||
errors.NotFound target_not_found = 2 [(tag.reason) = "not_found"];
|
||||
|
||||
// The provided unidentified authorization credential was invalid
|
||||
errors.FailedUnidentifiedAuthorization failed_unidentified_authorization = 3 [(tag.reason) = "failed_unidentified_authorization"];
|
||||
}
|
||||
}
|
||||
|
||||
message SetOneTimeEcPreKeysRequest {
|
||||
// The identity type (i.e. ACI/PNI) with which the keys in this request are
|
||||
// associated.
|
||||
common.IdentityType identity_type = 1;
|
||||
|
||||
// The unsigned EC pre-keys to be stored.
|
||||
repeated common.EcPreKey pre_keys = 2 [(require.size) = {min: 1, max: 100}];
|
||||
}
|
||||
|
||||
message SetOneTimeKemSignedPreKeysRequest {
|
||||
// The identity type (i.e. ACI/PNI) with which the keys in this request are
|
||||
// associated.
|
||||
common.IdentityType identity_type = 1;
|
||||
|
||||
// The KEM pre-keys to be stored.
|
||||
repeated common.KemSignedPreKey pre_keys = 2 [(require.size) = {min: 1, max: 100}];
|
||||
}
|
||||
|
||||
message SetEcSignedPreKeyRequest {
|
||||
// The identity type (i.e. ACI/PNI) with which this key is associated.
|
||||
common.IdentityType identity_type = 1;
|
||||
|
||||
// The signed EC pre-key itself.
|
||||
common.EcSignedPreKey signed_pre_key = 2 [(require.present) = true];
|
||||
}
|
||||
|
||||
message SetKemLastResortPreKeyRequest {
|
||||
// The identity type (i.e. ACI/PNI) with which this key is associated.
|
||||
common.IdentityType identity_type = 1;
|
||||
|
||||
// The signed KEM pre-key itself.
|
||||
common.KemSignedPreKey signed_pre_key = 2 [(require.present) = true];
|
||||
}
|
||||
|
||||
message SetPreKeyResponse {
|
||||
}
|
||||
|
||||
message CheckIdentityKeyRequest {
|
||||
// The service identifier of the account for which we want to check the associated identity key fingerprint.
|
||||
common.ServiceIdentifier target_identifier = 1;
|
||||
// The most significant 4 bytes of the SHA-256 hash of the identity key associated with the target account/identity type.
|
||||
bytes fingerprint = 2 [(require.exactlySize) = 4];
|
||||
}
|
||||
|
||||
message CheckIdentityKeyResponse {
|
||||
// The service identifier of the account for which there is a mismatch between the client and server identity key fingerprints.
|
||||
common.ServiceIdentifier target_identifier = 1;
|
||||
// The identity key that is stored by the server for the target account/identity type.
|
||||
bytes identity_key = 2;
|
||||
}
|
||||
65
pkg/signalmeow/protobuf/org/signal/chat/login_purchase.proto
Normal file
65
pkg/signalmeow/protobuf/org/signal/chat/login_purchase.proto
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright 2026 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
option java_multiple_files = true;
|
||||
|
||||
package org.signal.chat.purchase;
|
||||
|
||||
import "org/signal/chat/require.proto";
|
||||
import "org/signal/chat/errors.proto";
|
||||
import "org/signal/chat/tag.proto";
|
||||
import "org/signal/chat/subscriptions.proto";
|
||||
|
||||
// Service for one-time purchases of logins
|
||||
service LoginPurchase {
|
||||
option (require.auth) = AUTH_ONLY_ANONYMOUS;
|
||||
|
||||
// Obtain a ZK receipt credential for a completed one-time login payment.
|
||||
//
|
||||
// The receipt credential can then be presented at registration
|
||||
rpc CreateLoginReceiptCredential(CreateLoginReceiptCredentialRequest) returns (CreateLoginReceiptCredentialResponse) {}
|
||||
}
|
||||
|
||||
message CreateLoginReceiptCredentialRequest {
|
||||
// The payment processor. Currently, only GOOGLE_PLAY_BILLING and
|
||||
// APPLE_APP_STORE are supported.
|
||||
PaymentProvider processor = 1 [(require.specified) = true];
|
||||
|
||||
// The identifier of a completed purchase for a signal login within the
|
||||
// payment provider
|
||||
string purchase_identifier = 2 [(require.nonEmpty) = true];
|
||||
|
||||
// The receipt credential request. Subsequent retries to create a login
|
||||
// credential for the same purchase_identifier must use an identical
|
||||
// receipt_credential_request.
|
||||
//
|
||||
// Callers must validate that the generated receipt credential has the
|
||||
// following properties:
|
||||
//
|
||||
// - Level == 300 (The login level)
|
||||
// - ExpirationTime % 86400 == 0
|
||||
// - ExpirationTime == PurchaseTime + (5 * 366 * 86400) +/- (7 * 86400)
|
||||
bytes receipt_credential_request = 3 [(require.nonEmpty) = true];
|
||||
}
|
||||
|
||||
message CreateLoginReceiptCredentialResponse {
|
||||
message CreateLoginReceiptCredentialResult {
|
||||
bytes receipt_credential_response = 1;
|
||||
}
|
||||
|
||||
oneof response {
|
||||
CreateLoginReceiptCredentialResult result = 1;
|
||||
// The purchase is still pending with the payment provider. The client may retry later.
|
||||
errors.FailedPrecondition payment_still_processing = 2 [(tag.reason) = "payment_still_processing"];
|
||||
// The purchase did not complete successfully.
|
||||
PaymentRequired payment_required = 3 [(tag.reason) = "payment_required"];
|
||||
// The payment provider has no purchase with the provided purchase_identifier
|
||||
errors.NotFound payment_not_found = 4 [(tag.reason) = "payment_not_found"];
|
||||
// The purchase was already redeemed for a receipt credential, but with a different receipt credential request
|
||||
errors.FailedPrecondition receipt_already_issued = 5 [(tag.reason) = "receipt_already_issued"];
|
||||
}
|
||||
}
|
||||
437
pkg/signalmeow/protobuf/org/signal/chat/messages.proto
Normal file
437
pkg/signalmeow/protobuf/org/signal/chat/messages.proto
Normal file
|
|
@ -0,0 +1,437 @@
|
|||
/*
|
||||
* Copyright 2025 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
option java_multiple_files = true;
|
||||
|
||||
package org.signal.chat.messages;
|
||||
|
||||
import "google/protobuf/empty.proto";
|
||||
|
||||
import "org/signal/chat/common.proto";
|
||||
import "org/signal/chat/require.proto";
|
||||
import "org/signal/chat/errors.proto";
|
||||
import "org/signal/chat/tag.proto";
|
||||
|
||||
import "signalpb/SignalService.proto";
|
||||
|
||||
// Provides methods for sending "unsealed sender" messages.
|
||||
service Messages {
|
||||
|
||||
option (require.auth) = AUTH_ONLY_AUTHENTICATED;
|
||||
|
||||
// Sends an "unsealed sender" message to all devices linked to a single
|
||||
// destination account.
|
||||
//
|
||||
// The destination account must not be the same as the authenticated caller.
|
||||
// Callers should use `SendSyncMessage` to send messages to themselves.
|
||||
rpc SendMessage(SendAuthenticatedSenderMessageRequest) returns (SendMessageAuthenticatedSenderResponse) {}
|
||||
|
||||
// Sends a "sync" message to all other devices linked to the authenticated
|
||||
// sender's account.
|
||||
rpc SendSyncMessage(SendSyncMessageRequest) returns (SendMessageAuthenticatedSenderResponse) {}
|
||||
|
||||
// Retrieve messages for the authenticated device. When the caller receives
|
||||
// and successfully processes a message returned in a GetMessagesResponse they
|
||||
// must send a corresponding GetMessagesRequest indicating that the message
|
||||
// has been processed (an ack). Acks should only be sent for messages
|
||||
// delivered via the currently open RPC.
|
||||
//
|
||||
// Only the first GetMessagesRequest may contain request parameters that
|
||||
// configure the stream. The first request must not contain an ack.
|
||||
//
|
||||
// The server will keep the stream open until the client disconnects. Only
|
||||
// one GetMessages stream may be open per device. If a second GetMessages
|
||||
// stream is opened, the server may terminate any of the streams with
|
||||
// a STREAM_CLOSED error reason. A GetMessagesStreamClosed message will be
|
||||
// present in the error details.
|
||||
rpc GetMessages(stream GetMessagesRequest) returns (stream GetMessagesResponse) {}
|
||||
}
|
||||
|
||||
message GetMessagesRequest {
|
||||
message GetMessageOptions {
|
||||
// If present and true, the server will not deliver any messages with the
|
||||
// story flag set. This flag may only be set on the first GetMessagesRequest
|
||||
// sent from the client to the server in an RPC stream.
|
||||
bool drop_stories = 1;
|
||||
}
|
||||
oneof request {
|
||||
// Configuration options for the message stream. Required for the first
|
||||
// request of the stream, forbidden on subsequent reqeusts.
|
||||
GetMessageOptions options = 1;
|
||||
|
||||
// The server_guid of an envelope previously returned in a
|
||||
// GetMessagesResponse that has been successfully processed by the caller.
|
||||
// Forbidden on the first request of the stream, required on subsequent
|
||||
// requests.
|
||||
bytes server_guid_ack = 2;
|
||||
}
|
||||
}
|
||||
|
||||
// The reason why a GetMessages RPC is being closed by the server.
|
||||
message GetMessagesStreamClosed {
|
||||
oneof reason {
|
||||
// Another caller has opened a GetMessages stream for the same device.
|
||||
google.protobuf.Empty conflicting_stream = 1;
|
||||
}
|
||||
}
|
||||
|
||||
message GetMessagesResponse {
|
||||
oneof response {
|
||||
// A message. On successful receipt of an envelope the caller should ack
|
||||
// the envelope by sending a GetMessagesRequest with the envelope's server
|
||||
// guid. Acks should only be sent for envelopes received on the currently
|
||||
// open RPC.
|
||||
signalservice.Envelope envelope = 1;
|
||||
|
||||
// An indicator that all outstanding messages for the device have been
|
||||
// drained and acked by the client. The stream will remain open and continue
|
||||
// to deliver newly arrived messages.
|
||||
google.protobuf.Empty queue_empty = 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Provides methods for sending "sealed sender" messages.
|
||||
service MessagesAnonymous {
|
||||
|
||||
option (require.auth) = AUTH_ONLY_ANONYMOUS;
|
||||
|
||||
// Sends a "sealed sender" message to all devices linked to a single
|
||||
// destination account.
|
||||
//
|
||||
// If this RPC is authorized with an unidentified access key, it will fail
|
||||
// with an authorization failure if the credential is invalid OR if the
|
||||
// destination account was not found. If it is authorized using a group send
|
||||
// token, it will fail with an authorization failure if the credential is
|
||||
// invalid and with an destination not found error if the account does not
|
||||
// exist
|
||||
rpc SendSingleRecipientMessage(SendSealedSenderMessageRequest) returns (SendMessageResponse) {}
|
||||
|
||||
// Sends a "sealed sender" message with a common payload to all devices linked
|
||||
// to multiple destination accounts.
|
||||
rpc SendMultiRecipientMessage(SendMultiRecipientMessageRequest) returns (SendMultiRecipientMessageResponse) {}
|
||||
|
||||
// Sends a story message to devices linked to a single destination account.
|
||||
rpc SendStory(SendStoryMessageRequest) returns (SendMessageResponse) {}
|
||||
|
||||
// Sends a story message with a common payload to devices linked to devices
|
||||
// linked to multiple destination accounts.
|
||||
rpc SendMultiRecipientStory(SendMultiRecipientStoryRequest) returns (SendMultiRecipientMessageResponse) {}
|
||||
}
|
||||
|
||||
message IndividualRecipientMessageBundle {
|
||||
|
||||
// A message for an individual device linked to a destination account.
|
||||
message Message {
|
||||
|
||||
// The registration ID for the destination device.
|
||||
uint32 registration_id = 1 [(require.range).max = 0x3fff];
|
||||
|
||||
// The content of the message to deliver to the destination device.
|
||||
bytes payload = 2 [(require.size) = {min: 1, max: 262144}]; // 256 KiB
|
||||
|
||||
// The message type of the message. If this message is part of an
|
||||
// unidentified send, this must be UNIDENTIFIED_SENDER
|
||||
SendMessageType type = 3;
|
||||
}
|
||||
|
||||
// The time, in milliseconds since the epoch, at which this message was
|
||||
// originally sent from the perspective of the sender. Note that the maximum
|
||||
// allowable timestamp for JavaScript clients is less than Long.MAX_VALUE; see
|
||||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date#the_epoch_timestamps_and_invalid_date
|
||||
// for additional details and discussion.
|
||||
uint64 timestamp = 1 [(require.range).min = 1, (require.range).max = 8640000000000000];
|
||||
|
||||
// A map of device IDs to individual messages. Generally, callers must include
|
||||
// one message for each device linked to the destination account. In cases of
|
||||
// "sync messages" where a sender is distributing information to other devices
|
||||
// linked to the sender's account, senders may omit a message for the sending
|
||||
// device.
|
||||
map<uint32, Message> messages = 2 [(require.nonEmpty) = true];
|
||||
}
|
||||
|
||||
enum SendMessageType {
|
||||
UNSPECIFIED = 0;
|
||||
|
||||
// A double-ratchet message represents a "normal," "unsealed-sender" message
|
||||
// encrypted using the Double Ratchet within an established Signal session.
|
||||
DOUBLE_RATCHET = 1;
|
||||
|
||||
// A prekey message begins a new Signal session. The `content` of a prekey
|
||||
// message is a superset of a double-ratchet message's `content` and
|
||||
// contains the sender's identity public key and information identifying the
|
||||
// pre-keys used in the message's ciphertext.
|
||||
PREKEY_MESSAGE = 2;
|
||||
|
||||
// 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 = 3;
|
||||
|
||||
// An unidentified sender message is an encrypted message. No other
|
||||
// information about the type of the encrypted message is known to the server.
|
||||
//
|
||||
// Unidenitfied sender messages require an unidentified access token or a
|
||||
// group send endorsement token to prove the unidentified sender is authorized
|
||||
// to send messages to the destination.
|
||||
UNIDENTIFIED_SENDER = 4;
|
||||
}
|
||||
|
||||
message SendAuthenticatedSenderMessageRequest {
|
||||
|
||||
// The service identifier of the account to which to deliver the message.
|
||||
common.ServiceIdentifier destination = 1;
|
||||
|
||||
// If true, this message will only be delivered to destination devices that
|
||||
// have an active message delivery channel with a Signal server.
|
||||
bool ephemeral = 2;
|
||||
|
||||
// Indicates whether this message is urgent and should trigger a high-priority
|
||||
// notification if the destination device does not have an active message
|
||||
// delivery channel with a Signal server
|
||||
bool urgent = 3;
|
||||
|
||||
// The messages to send to the destination account.
|
||||
IndividualRecipientMessageBundle messages = 4;
|
||||
}
|
||||
|
||||
message SendMessageAuthenticatedSenderResponse {
|
||||
|
||||
// The outcome of the message delivery
|
||||
oneof response {
|
||||
|
||||
// The message was successfully delivered to all destination devices
|
||||
google.protobuf.Empty success = 1;
|
||||
|
||||
// A list of discrepancies between the destination devices identified in a
|
||||
// request to send a message and the devices that are actually linked to an
|
||||
// account.
|
||||
MismatchedDevices mismatched_devices = 2 [(tag.reason) = "mismatched_devices"];
|
||||
|
||||
// A description of a challenge callers must complete before sending
|
||||
// additional messages.
|
||||
ChallengeRequired challenge_required = 3 [(tag.reason) = "challenge_required"];
|
||||
|
||||
// The destination account did not exist
|
||||
errors.NotFound destination_not_found = 4 [(tag.reason) = "destination_not_found"];
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
message SendSyncMessageRequest {
|
||||
|
||||
// Indicates whether this message is urgent and should trigger a high-priority
|
||||
// notification if the destination device does not have an active message
|
||||
// delivery channel with a Signal server
|
||||
bool urgent = 1;
|
||||
|
||||
// The messages to send to the destination account.
|
||||
IndividualRecipientMessageBundle messages = 2;
|
||||
}
|
||||
|
||||
message SendSealedSenderMessageRequest {
|
||||
|
||||
// The service identifier of the account to which to deliver the message.
|
||||
common.ServiceIdentifier destination = 1;
|
||||
|
||||
// If true, this message will only be delivered to destination devices that
|
||||
// have an active message delivery channel with a Signal server.
|
||||
bool ephemeral = 2;
|
||||
|
||||
// Indicates whether this message is urgent and should trigger a high-priority
|
||||
// notification if the destination device does not have an active message
|
||||
// delivery channel with a Signal server
|
||||
bool urgent = 3;
|
||||
|
||||
// The messages to send to the destination account.
|
||||
IndividualRecipientMessageBundle messages = 4;
|
||||
|
||||
// A means to authorize the request.
|
||||
oneof authorization {
|
||||
|
||||
// The unidentified access key (UAK) for the destination account.
|
||||
bytes unidentified_access_key = 5 [(require.exactlySize) = 16];
|
||||
|
||||
// A group send endorsement token for the destination account.
|
||||
bytes group_send_token = 6;
|
||||
|
||||
// The destination account allows unrestricted unidentified access
|
||||
google.protobuf.Empty unrestricted_access = 7;
|
||||
}
|
||||
}
|
||||
|
||||
message SendStoryMessageRequest {
|
||||
|
||||
// The service identifier of the account to which to deliver the message.
|
||||
common.ServiceIdentifier destination = 1;
|
||||
|
||||
// Indicates whether this message is urgent and should trigger a high-priority
|
||||
// notification if the destination device does not have an active message
|
||||
// delivery channel with a Signal server
|
||||
bool urgent = 2;
|
||||
|
||||
// The messages to send to the destination account.
|
||||
IndividualRecipientMessageBundle messages = 3;
|
||||
}
|
||||
|
||||
message SendMessageResponse {
|
||||
|
||||
// The outcome of the message delivery
|
||||
oneof response {
|
||||
|
||||
// The message was successfully delivered to all destination devices
|
||||
google.protobuf.Empty success = 1;
|
||||
|
||||
// A list of discrepancies between the destination devices identified in a
|
||||
// request to send a message and the devices that are actually linked to an
|
||||
// account.
|
||||
MismatchedDevices mismatched_devices = 2 [(tag.reason) = "mismatched_devices"];
|
||||
|
||||
// The provided unidentified authorization credential was invalid
|
||||
errors.FailedUnidentifiedAuthorization failed_unidentified_authorization = 3 [(tag.reason) = "failed_unidentified_authorization"];
|
||||
|
||||
// The destination account did not exist
|
||||
errors.NotFound destination_not_found = 4 [(tag.reason) = "destination_not_found"];
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
message MultiRecipientMessage {
|
||||
|
||||
// The time, in milliseconds since the epoch, at which this message was
|
||||
// originally sent from the perspective of the sender. Note that the maximum
|
||||
// allowable timestamp for JavaScript clients is less than Long.MAX_VALUE; see
|
||||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date#the_epoch_timestamps_and_invalid_date
|
||||
// for additional details and discussion.
|
||||
uint64 timestamp = 1 [(require.range).min = 1, (require.range).max = 8640000000000000];
|
||||
|
||||
// The serialized multi-recipient message payload.
|
||||
bytes payload = 2 [(require.size).max = 762144]; // 256 KiB payload + (5000 * 100) of overhead
|
||||
}
|
||||
|
||||
message SendMultiRecipientMessageRequest {
|
||||
|
||||
// If true, this message will only be delivered to destination devices that
|
||||
// have an active message delivery channel with a Signal server.
|
||||
bool ephemeral = 1;
|
||||
|
||||
// Indicates whether this message is urgent and should trigger a high-priority
|
||||
// notification if the destination device does not have an active message
|
||||
// delivery channel with a Signal server
|
||||
bool urgent = 2;
|
||||
|
||||
// The multi-recipient message to send to all destination accounts and
|
||||
// devices.
|
||||
MultiRecipientMessage message = 3;
|
||||
|
||||
// A group send endorsement token for the destination account.
|
||||
bytes group_send_token = 4 [(require.nonEmpty) = true];
|
||||
}
|
||||
|
||||
message SendMultiRecipientStoryRequest {
|
||||
|
||||
// Indicates whether this message is urgent and should trigger a high-priority
|
||||
// notification if the destination device does not have an active message
|
||||
// delivery channel with a Signal server
|
||||
bool urgent = 1;
|
||||
|
||||
// The multi-recipient story message to send to all destination accounts and
|
||||
// devices.
|
||||
MultiRecipientMessage message = 2;
|
||||
}
|
||||
|
||||
message MultiRecipientSuccess {
|
||||
// A list of destination service identifiers that could not be resolved to
|
||||
// registered Signal accounts. The message in the original request was sent
|
||||
// to all service identifiers/devices in the original request except for the
|
||||
// destination devices associated with the service identifiers in this list.
|
||||
repeated common.ServiceIdentifier unresolved_recipients = 1;
|
||||
}
|
||||
|
||||
message SendMultiRecipientMessageResponse {
|
||||
|
||||
// The outcome of the message delivery
|
||||
oneof response {
|
||||
// The message was sent to at least some of the destination accounts/devices
|
||||
// identified in the original request.
|
||||
MultiRecipientSuccess success = 1;
|
||||
|
||||
// A list of sets of discrepancies between the destination devices
|
||||
// identified in a request to send a message and the devices that are
|
||||
// actually linked to a destination account.
|
||||
MultiRecipientMismatchedDevices mismatched_devices = 2 [(tag.reason) = "mismatched_devices"];
|
||||
|
||||
// The provided unidentified authorization credential was invalid
|
||||
errors.FailedUnidentifiedAuthorization failed_unidentified_authorization = 3 [(tag.reason) = "failed_unidentified_authorization"];
|
||||
}
|
||||
}
|
||||
|
||||
message MismatchedDevices {
|
||||
|
||||
// The service identifier to which the devices named in this object are
|
||||
// linked.
|
||||
common.ServiceIdentifier service_identifier = 1;
|
||||
|
||||
// A list of device IDs that are linked to the destination account, but were
|
||||
// not included in the collection of messages bound for the destination
|
||||
// account.
|
||||
repeated uint32 missing_devices = 2 [(require.each) = {range: {max: 0x7f}}];
|
||||
|
||||
// A list of device IDs that were included in the collection of messages bound
|
||||
// for the destination account, but are not currently linked to the
|
||||
// destination account.
|
||||
repeated uint32 extra_devices = 3 [(require.each) = {range: {max: 0x7f}}];
|
||||
|
||||
// A list of device IDs that present in the collection of messages bound for
|
||||
// the destination account and are linked to the destination account, but have
|
||||
// a different registration ID than the registration ID presented by the
|
||||
// sender (indicating that the destination device has likely been replaced by
|
||||
// another device).
|
||||
repeated uint32 stale_devices = 4 [(require.each) = {range: {max: 0x7f}}];
|
||||
}
|
||||
|
||||
message MultiRecipientMismatchedDevices {
|
||||
|
||||
// A list of sets of discrepancies between the destination devices identified
|
||||
// in a request to send a message and the devices that are actually linked to
|
||||
// a destination account.
|
||||
repeated MismatchedDevices mismatched_devices = 1;
|
||||
}
|
||||
|
||||
message ChallengeRequired {
|
||||
|
||||
enum ChallengeType {
|
||||
UNSPECIFIED = 0;
|
||||
|
||||
// A challenge that callers can fulfill by completing a captcha.
|
||||
CAPTCHA = 1;
|
||||
|
||||
// A challenge that callers can fulfill by supplying a token delivered via
|
||||
// push notification.
|
||||
PUSH_CHALLENGE = 2;
|
||||
};
|
||||
|
||||
// An opaque token identifying this challenge request. Clients must generally
|
||||
// submit this token when submitting a challenge response.
|
||||
string token = 1;
|
||||
|
||||
// A list of challenge types callers may choose to complete to resolve the
|
||||
// challenge requirement. May be empty, in which case callers cannot resolve
|
||||
// the challenge by any means other than waiting.
|
||||
repeated ChallengeType challenge_options = 2;
|
||||
|
||||
// A duration (in seconds) after which the challenge requirement may be
|
||||
// resolved by simply waiting. May not be set if the challenge cannot be
|
||||
// resolved by waiting.
|
||||
optional uint64 retry_after_seconds = 3;
|
||||
}
|
||||
169
pkg/signalmeow/protobuf/org/signal/chat/one_time_donations.proto
Normal file
169
pkg/signalmeow/protobuf/org/signal/chat/one_time_donations.proto
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
* Copyright 2026 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
option java_multiple_files = true;
|
||||
|
||||
package org.signal.chat.purchase;
|
||||
|
||||
import "org/signal/chat/require.proto";
|
||||
import "org/signal/chat/errors.proto";
|
||||
import "org/signal/chat/tag.proto";
|
||||
import "org/signal/chat/subscriptions.proto";
|
||||
|
||||
// Service for making one-time donation payments (boost and gift)
|
||||
//
|
||||
// Configuration for one-time donations can be found in ProductConfiguration.
|
||||
service OneTimeDonations {
|
||||
option (require.auth) = AUTH_ONLY_ANONYMOUS;
|
||||
|
||||
// Create a Stripe payment intent and return a client secret that can be used to complete the payment.
|
||||
// Once the payment is complete, the paymentIntentId can be used with CreateBoostReceiptCredentials
|
||||
rpc CreateBoost(CreateBoostRequest) returns (CreateBoostResponse) {}
|
||||
|
||||
// Create a PayPal one-time payment.
|
||||
// Once the payment is complete, call ConfirmPayPalBoost with the payment ID and token
|
||||
rpc CreatePayPalBoost(CreatePayPalBoostRequest) returns (CreatePayPalBoostResponse) {}
|
||||
|
||||
// Confirm a PayPal one-time payment
|
||||
rpc ConfirmPayPalBoost(ConfirmPayPalBoostRequest) returns (ConfirmPayPalBoostResponse) {}
|
||||
|
||||
// Obtain a ZK receipt credential for a completed one-time donation payment.
|
||||
// The receipt credential can then be used to redeem the one-time donation entitlement
|
||||
// via Donations.RedeemReceipt
|
||||
rpc CreateBoostReceiptCredentials(CreateBoostReceiptCredentialsRequest) returns (CreateBoostReceiptCredentialsResponse) {}
|
||||
}
|
||||
|
||||
// The amount is below the minimum for the currency.
|
||||
message AmountBelowMinimumError {
|
||||
// The minimum amount for the currency
|
||||
string minimum = 1;
|
||||
}
|
||||
|
||||
// The SEPA Direct Debit amount exceeds the allowed maximum.
|
||||
message AmountAboveSepaLimitError {
|
||||
// The maximum amount for a SEPA transaction
|
||||
string maximum = 1;
|
||||
}
|
||||
|
||||
message CreateBoostRequest {
|
||||
// ISO 4217 currency code, case-insensitive (e.g. "usd", "EUR")
|
||||
string currency = 1 [(require.exactlySize) = 3];
|
||||
// The amount to pay in the [currency's minor unit](https://docs.stripe.com/currencies#minor-units)
|
||||
uint64 amount = 2 [(require.range).min = 1];
|
||||
// The level for the boost payment
|
||||
uint64 level = 3 [(require.range).min = 1];
|
||||
// The payment method
|
||||
PaymentMethod payment_method = 4 [(require.specified) = true];
|
||||
// A donation permit retrieved from Donations.createDonationPermit
|
||||
bytes donation_permit = 5 [(require.nonEmpty) = true];
|
||||
}
|
||||
|
||||
message CreateBoostResponse {
|
||||
oneof response {
|
||||
// A client secret that can be used to complete a stripe PaymentIntent
|
||||
string client_secret = 1;
|
||||
// The amount is below the minimum for the currency
|
||||
AmountBelowMinimumError amount_below_minimum = 2 [(tag.reason) = "amount_below_minimum"];
|
||||
// The amount exceeds the maximum for SEPA Direct Debit
|
||||
AmountAboveSepaLimitError amount_above_sepa_limit = 3 [(tag.reason) = "amount_above_sepa_limit"];
|
||||
// The requested currency is not supported for the given payment method
|
||||
errors.FailedPrecondition unsupported_currency = 4 [(tag.reason) = "unsupported_currency"];
|
||||
// The requested level is not a valid one-time donation level
|
||||
errors.FailedPrecondition unsupported_level = 5 [(tag.reason) = "unsupported_level"];
|
||||
// Donation permit was invalid or already spent
|
||||
errors.FailedZkAuthentication permit_rejected = 6 [(tag.reason) = "permit_rejected"];
|
||||
// The amount in the specified currency is not supported by the payment provider
|
||||
errors.FailedPrecondition invalid_amount = 7 [(tag.reason) = "invalid_amount"];
|
||||
}
|
||||
}
|
||||
|
||||
message CreatePayPalBoostRequest {
|
||||
// ISO 4217 currency code, case-insensitive (e.g. "usd", "EUR")
|
||||
string currency = 1 [(require.exactlySize) = 3];
|
||||
// Amount in the currency's minor unit (e.g. cents for USD), must be >= 1
|
||||
uint64 amount = 2 [(require.range).min = 1];
|
||||
// Donation level.
|
||||
uint64 level = 3 [(require.range).min = 1];
|
||||
// URL to redirect the user to after PayPal approval
|
||||
string return_url = 4 [(require.nonEmpty) = true];
|
||||
// URL to redirect the user to if they cancel
|
||||
string cancel_url = 5 [(require.nonEmpty) = true];
|
||||
}
|
||||
|
||||
message CreatePayPalBoostResponse {
|
||||
message CreatePayPalBoostResult {
|
||||
string approval_url = 1;
|
||||
string payment_id = 2;
|
||||
}
|
||||
oneof response {
|
||||
CreatePayPalBoostResult result = 1;
|
||||
// The amount is below the minimum for the currency
|
||||
AmountBelowMinimumError amount_below_minimum = 2 [(tag.reason) = "amount_below_minimum"];
|
||||
// The requested currency is not supported for PayPal
|
||||
errors.FailedPrecondition unsupported_currency = 3 [(tag.reason) = "unsupported_currency"];
|
||||
// The requested level is not a valid one-time donation level
|
||||
errors.FailedPrecondition unsupported_level = 4 [(tag.reason) = "unsupported_level"];
|
||||
}
|
||||
}
|
||||
|
||||
message ConfirmPayPalBoostRequest {
|
||||
// ISO 4217 currency code, case-insensitive (e.g. "usd", "EUR")
|
||||
string currency = 1 [(require.exactlySize) = 3];
|
||||
// Amount in the currency's minor unit, must be >= 1
|
||||
uint64 amount = 2 [(require.range).min = 1];
|
||||
// Donation level.
|
||||
uint64 level = 3 [(require.range).min = 1];
|
||||
// PayPal payer ID from the approval redirect
|
||||
string payer_id = 4 [(require.nonEmpty) = true];
|
||||
// PayPal payment ID (PAYID-…) from CreatePayPalBoost
|
||||
string payment_id = 5 [(require.nonEmpty) = true];
|
||||
// PayPal payment token (EC-…) from the approval redirect
|
||||
string payment_token = 6 [(require.nonEmpty) = true];
|
||||
}
|
||||
|
||||
message ConfirmPayPalBoostResponse {
|
||||
message ConfirmPayPalBoostResult {
|
||||
string payment_id = 1;
|
||||
}
|
||||
oneof response {
|
||||
ConfirmPayPalBoostResult result = 1;
|
||||
// The amount is below the minimum for the currency
|
||||
AmountBelowMinimumError amount_below_minimum = 2 [(tag.reason) = "amount_below_minimum"];
|
||||
// The requested currency is not supported for PayPal
|
||||
errors.FailedPrecondition unsupported_currency = 3 [(tag.reason) = "unsupported_currency"];
|
||||
// The requested level is not a valid one-time donation level
|
||||
errors.FailedPrecondition unsupported_level = 4 [(tag.reason) = "unsupported_level"];
|
||||
// The payment failed; see charge failure details
|
||||
ChargeFailure charge_failure = 5 [(tag.reason) = "charge_failure"];
|
||||
}
|
||||
}
|
||||
|
||||
message CreateBoostReceiptCredentialsRequest {
|
||||
// a payment ID from the processor
|
||||
string payment_intent_id = 1 [(require.nonEmpty) = true];
|
||||
// ZK blind-signature receipt credential request bytes
|
||||
bytes receipt_credential_request = 2 [(require.nonEmpty) = true];
|
||||
// The processor that handled the payment
|
||||
PaymentProvider processor = 3 [(require.specified) = true];
|
||||
}
|
||||
|
||||
message CreateBoostReceiptCredentialsResponse {
|
||||
message CreateBoostReceiptCredentialsResult {
|
||||
bytes receipt_credential_response = 1;
|
||||
}
|
||||
oneof response {
|
||||
CreateBoostReceiptCredentialsResult result = 1;
|
||||
// Payment is still processing; client should retry
|
||||
errors.FailedPrecondition payment_still_processing = 2 [(tag.reason) = "payment_still_processing"];
|
||||
// Payment failed
|
||||
PaymentRequired payment_required = 3 [(tag.reason) = "payment_required"];
|
||||
// Payment intent not found
|
||||
errors.NotFound payment_not_found = 4 [(tag.reason) = "payment_not_found"];
|
||||
// A receipt credential was already issued for this payment
|
||||
errors.FailedPrecondition receipt_already_issued = 5 [(tag.reason) = "receipt_already_issued"];
|
||||
}
|
||||
}
|
||||
37
pkg/signalmeow/protobuf/org/signal/chat/payments.proto
Normal file
37
pkg/signalmeow/protobuf/org/signal/chat/payments.proto
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright 2023 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
option java_multiple_files = true;
|
||||
|
||||
package org.signal.chat.payments;
|
||||
|
||||
import "org/signal/chat/require.proto";
|
||||
|
||||
// Provides methods for working with payments.
|
||||
service Payments {
|
||||
option (require.auth) = AUTH_ONLY_AUTHENTICATED;
|
||||
|
||||
|
||||
rpc GetCurrencyConversions(GetCurrencyConversionsRequest) returns (GetCurrencyConversionsResponse) {}
|
||||
}
|
||||
|
||||
message GetCurrencyConversionsRequest {
|
||||
}
|
||||
|
||||
message GetCurrencyConversionsResponse {
|
||||
|
||||
message CurrencyConversionEntity {
|
||||
|
||||
string base = 1;
|
||||
|
||||
map<string, string> conversions = 2;
|
||||
}
|
||||
|
||||
uint64 timestamp = 1;
|
||||
|
||||
repeated CurrencyConversionEntity currencies = 2;
|
||||
}
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Copyright 2026 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
option java_multiple_files = true;
|
||||
|
||||
package org.signal.chat.purchase;
|
||||
|
||||
import "org/signal/chat/require.proto";
|
||||
import "org/signal/chat/subscriptions.proto";
|
||||
|
||||
// Retrieve product metadata for one-time donations, subscriptions, and backups
|
||||
service ProductConfiguration {
|
||||
option (require.auth) = AUTH_ONLY_ANONYMOUS;
|
||||
|
||||
// Returns configuration for donation subscriptions, backup subscriptions, and one-time donation (
|
||||
// "boost" and "gift") minimum and suggested amounts. Badges are referenced by ID only; resolve those
|
||||
// IDs to full badge details via RemoteConfiguration.GetBadges.
|
||||
rpc GetConfiguration(GetConfigurationRequest) returns (GetConfigurationResponse) {}
|
||||
}
|
||||
|
||||
message GetConfigurationRequest {}
|
||||
|
||||
message GetConfigurationResponse {
|
||||
// Map of lower-cased ISO 3 currency codes to currency-specific configuration
|
||||
map<string, CurrencyConfiguration> currencies = 1;
|
||||
// Map of numeric donation level IDs to level-specific badge configuration
|
||||
map<uint64, LevelConfiguration> badge_levels = 2;
|
||||
// Configuration for backup subscription options
|
||||
BackupConfiguration backup = 3;
|
||||
// Maximum value of a one-time SEPA donation
|
||||
string sepa_maximum_euros = 4;
|
||||
// Configuration for one-time Signal Login purchases
|
||||
LoginConfiguration login = 5;
|
||||
}
|
||||
|
||||
message AmountList {
|
||||
// NOTE: this is a string instead of a numeric type because it is intended
|
||||
// for display purposes only
|
||||
repeated string amounts = 1;
|
||||
}
|
||||
|
||||
message CurrencyConfiguration {
|
||||
// Minimum one-time donation
|
||||
// NOTE: this is a string instead of a numeric type because it is intended
|
||||
// for display purposes only
|
||||
string minimum = 1;
|
||||
// Map of one-time donation level IDs to suggested amounts
|
||||
map<uint64, AmountList> one_time = 2;
|
||||
// Map of subscription level IDs to the amount charged
|
||||
map<uint64, string> subscription = 3;
|
||||
// Map of backup subscription level IDs to the amount charged
|
||||
map<uint64, string> backup_subscription = 4;
|
||||
repeated PaymentMethod supported_payment_methods = 5;
|
||||
}
|
||||
|
||||
message LevelConfiguration {
|
||||
// The ID of the badge awarded at this level. Resolve to full badge details
|
||||
// via RemoteConfiguration.GetBadges.
|
||||
string badge_id = 1;
|
||||
|
||||
// The duration for which a badge is valid. Present only for
|
||||
// one-time (boost, gift) badges
|
||||
optional uint64 badge_duration_seconds = 2;
|
||||
}
|
||||
|
||||
// Configuration for a backup level - use to present appropriate client interfaces
|
||||
message BackupLevelConfiguration {
|
||||
// The amount of media storage in bytes that a paying subscriber may store
|
||||
uint64 storage_allowance_bytes = 1;
|
||||
// The play billing productID associated with this backup level
|
||||
string play_product_id = 2;
|
||||
// The duration, in days, for which your backed up media is retained on the server after you stop refreshing with a paid credential
|
||||
uint64 media_ttl_days = 3;
|
||||
}
|
||||
|
||||
message BackupConfiguration {
|
||||
// A map of numeric backup level IDs to level-specific backup configuration
|
||||
map<uint64, BackupLevelConfiguration> levels = 1;
|
||||
// The number of days of media a free tier backup user gets
|
||||
uint64 free_tier_media_days = 2;
|
||||
}
|
||||
|
||||
// Configuration for one-time Signal Login purchases
|
||||
message LoginConfiguration {
|
||||
// The receipt level associated with a Signal Login purchase
|
||||
uint64 level = 1;
|
||||
// The play billing productID associated with a Signal Login purchase
|
||||
string play_product_id = 2;
|
||||
// The App Store productID associated with a Signal Login purchase
|
||||
string app_store_product_id = 3;
|
||||
}
|
||||
406
pkg/signalmeow/protobuf/org/signal/chat/profile.proto
Normal file
406
pkg/signalmeow/protobuf/org/signal/chat/profile.proto
Normal file
|
|
@ -0,0 +1,406 @@
|
|||
/*
|
||||
* Copyright 2023 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
option java_multiple_files = true;
|
||||
|
||||
package org.signal.chat.profile;
|
||||
|
||||
import "google/protobuf/empty.proto";
|
||||
|
||||
import "org/signal/chat/common.proto";
|
||||
import "org/signal/chat/errors.proto";
|
||||
import "org/signal/chat/require.proto";
|
||||
import "org/signal/chat/tag.proto";
|
||||
|
||||
// Provides methods for working with profiles and profile-related data.
|
||||
service Profile {
|
||||
option (require.auth) = AUTH_ONLY_AUTHENTICATED;
|
||||
|
||||
// Sets profile data and, if needed, returns credentials used by clients to upload a v1 avatar.
|
||||
rpc SetProfile(SetProfileRequest) returns (SetProfileResponse) {}
|
||||
|
||||
// Retrieves profile data. Callers with an unidentified access key for the account
|
||||
// should use the version of this method in `ProfileAnonymous` instead.
|
||||
rpc GetProfile(GetProfileRequest) returns (GetProfileResponse) {}
|
||||
|
||||
// Returns anonymous credentials that may be presented with avatar operations in ProfilesAnonymous
|
||||
//
|
||||
// Note: `Accounts.SetZkCredentialKey` is a pre-requisite for this RPC
|
||||
rpc GetAvatarCredentials(GetAvatarCredentialsRequest) returns (GetAvatarCredentialsResponse) {}
|
||||
}
|
||||
|
||||
// Provides methods for working with profiles and profile-related data using "unidentified access"
|
||||
// credentials. Callers must not submit any self-identifying credentials
|
||||
// when calling methods in this service and must instead present the targeted account's
|
||||
// unidentified access key as an anonymous authentication mechanism. Callers
|
||||
// without an unidentified access key should use the equivalent, authenticated
|
||||
// methods in `Profile` instead.
|
||||
service ProfileAnonymous {
|
||||
option (require.auth) = AUTH_ONLY_ANONYMOUS;
|
||||
|
||||
// Retrieves profile data.
|
||||
rpc GetProfile(GetProfileAnonymousRequest) returns (GetProfileAnonymousResponse) {}
|
||||
|
||||
// Retrieves a profile key credential.
|
||||
rpc GetExpiringProfileKeyCredential(GetExpiringProfileKeyCredentialAnonymousRequest) returns (GetExpiringProfileKeyCredentialAnonymousResponse) {}
|
||||
|
||||
// Returns credentials to upload a v2 avatar. After uploading the avatar, the client
|
||||
// must call SetProfile with the new avatar URL in the encrypted `data`.
|
||||
//
|
||||
// Because avatars are uploaded anonymously, they have an expiration equal to the
|
||||
// idle account expiration. Clients must periodically (recommended: every 90 days)
|
||||
// call ExtendAvatarTTL to extend the TTl.
|
||||
//
|
||||
// Note: any existing avatar associated with these credentials will be deleted immediately
|
||||
rpc GetAvatarUploadForm(GetAvatarUploadFormRequest) returns (GetAvatarUploadFormResponse) {}
|
||||
|
||||
// Extends the TTL of the avatar currently associated with the request’s avatar auth credential
|
||||
rpc ExtendAvatarTTL(ExtendAvatarTTLRequest) returns (ExtendAvatarTTLResponse) {}
|
||||
|
||||
// Deletes the avatar currently associated with the request’s avatar auth credential.
|
||||
//
|
||||
// Clients must also call SetProfile to remove the avatar from the encrypted `data`.
|
||||
rpc DeleteAvatar(DeleteAvatarRequest) returns (DeleteAvatarResponse) {}
|
||||
}
|
||||
|
||||
message SetProfileV1Request {
|
||||
enum AvatarChange {
|
||||
AVATAR_CHANGE_UNCHANGED = 0;
|
||||
AVATAR_CHANGE_CLEAR = 1;
|
||||
AVATAR_CHANGE_UPDATE = 2;
|
||||
}
|
||||
|
||||
// The ciphertext of a name that users must set on the profile.
|
||||
bytes name = 1 [(require.exactlySize) = 81, (require.exactlySize) = 285];
|
||||
|
||||
// An enum to indicate what change, if any, is made to the avatar with this request.
|
||||
AvatarChange avatar_change = 2;
|
||||
|
||||
// The ciphertext of an emoji that users can set on their profile.
|
||||
bytes about_emoji = 3 [(require.exactlySize) = 0, (require.exactlySize) = 60];
|
||||
|
||||
// The ciphertext of a description that users can set on their profile.
|
||||
bytes about = 4 [(require.exactlySize) = 0, (require.exactlySize) = 156, (require.exactlySize) = 282, (require.exactlySize) = 540];
|
||||
|
||||
// The ciphertext of the phone-number sharing setting on the profile. 29-byte encrypted boolean.
|
||||
bytes phone_number_sharing = 6 [(require.exactlySize) = 29];
|
||||
}
|
||||
|
||||
message SetProfileRequest {
|
||||
|
||||
// The profile version. Required.
|
||||
bytes version = 1 [(require.exactlySize) = 32];
|
||||
|
||||
// The ciphertext of a serialized Profile protobuf. Required.
|
||||
// 937 max length = 909 plaintext serialization + 28 bytes encryption overhead
|
||||
bytes data = 2 [(require.nonEmpty) = true, (require.size).max = 937];
|
||||
|
||||
// The SHA-256 hash of the Profile ciphertext being replaced.
|
||||
// This is used an optimistic lock against concurrent changes.
|
||||
//
|
||||
// Optional, if this is the initial request to create a version.
|
||||
bytes expected_current_data_hash = 3 [(require.exactlySize) = 0, (require.exactlySize) = 32];
|
||||
|
||||
// The current profile version being updated.
|
||||
// This is used as an optimistic lock against concurrent changes.
|
||||
//
|
||||
// Optional, if there is no current profile version for the account.
|
||||
bytes expected_current_version = 4 [(require.exactlySize) = 0, (require.exactlySize) = 32];
|
||||
|
||||
// The ciphertext of the MobileCoin wallet ID on the profile.
|
||||
bytes payment_address = 5 [(require.exactlySize) = 0, (require.exactlySize) = 582];
|
||||
|
||||
// A list of badge IDs associated with the profile.
|
||||
repeated string badge_ids = 6;
|
||||
|
||||
// The profile key commitment. Used to issue a profile key credential response.
|
||||
//
|
||||
// Required during the v1 -> v2 migration period. Afterwards will be optional, if this is an update to an existing version.
|
||||
bytes commitment = 7 [(require.exactlySize) = 0, (require.exactlySize) = 97];
|
||||
|
||||
// An embedded v1 request. Required during the v1 -> v2 migration period.
|
||||
//
|
||||
// Because this is a temporary field during the migration, it has the highest
|
||||
// field number without serialization overhead. This is purely aesthetic.
|
||||
SetProfileV1Request v1Request = 15 [(require.present) = true];
|
||||
|
||||
// next: 8
|
||||
}
|
||||
|
||||
// Indicates that the account is not permitted to set a payment address,
|
||||
// due to a disallowed country prefix on the account's phone number.
|
||||
message PaymentsForbiddenInRegion {}
|
||||
|
||||
// Indicates that the account does not have the Profiles v2 capability, which
|
||||
// is required to call Profiles.SetProfile
|
||||
message ProfilesV2CapabilityRequired {}
|
||||
|
||||
|
||||
message SetProfileResult {
|
||||
// If the request included a v1 avatar change, this field contains the policy
|
||||
// and credential used by clients to upload an avatar to the CDN.
|
||||
//
|
||||
// Because this is a temporary field during the migration, it has the highest
|
||||
// field number without serialization overhead. This is purely aesthetic.
|
||||
optional common.S3UploadForm v1_avatar_upload_form = 15;
|
||||
|
||||
// next: 1
|
||||
}
|
||||
|
||||
message SetProfileResponse {
|
||||
oneof response {
|
||||
SetProfileResult result = 1;
|
||||
// The current data hash did not match the request's expectation, indicating
|
||||
// another device on the account may have written an update the caller does not know about.
|
||||
errors.FailedPrecondition expected_data_write_conflict = 2 [(tag.reason) = "expected_data_write_conflict"];
|
||||
// Payments are not permitted in the account's region, based on its phone
|
||||
// number or the caller's IP address if the account does not have a phone
|
||||
// number. The request should be retried without `payment_address.
|
||||
PaymentsForbiddenInRegion payments_forbidden_in_region = 3 [(tag.reason) = "payments_forbidden_in_region"];
|
||||
// The current version did not match the request's expectation, indicating
|
||||
// another device on the account may have created a new version the caller does not know about.
|
||||
errors.FailedPrecondition expected_version_write_conflict = 4 [(tag.reason) = "expected_version_write_conflict"];
|
||||
|
||||
// Because this is a temporary field during the migration, it has the highest
|
||||
// field number without serialization overhead. This is purely aesthetic.
|
||||
ProfilesV2CapabilityRequired profiles_v2_capability_required = 15 [(tag.reason) = "profiles_v2_capability_required"];
|
||||
|
||||
// next: 4
|
||||
}
|
||||
}
|
||||
|
||||
message GetProfileRequest {
|
||||
// The ACI of the account for which to get profile data.
|
||||
common.ServiceIdentifier account_identifier = 1 [(require.present) = true, (require.identityType) = IDENTITY_TYPE_ACI];
|
||||
// The profile version to retrieve.
|
||||
bytes version = 2 [(require.exactlySize) = 32];
|
||||
|
||||
// The `etag` from the previous request for this Profile version. If
|
||||
// unchanged, the response will omit `profile` and `etag_matched` will be
|
||||
// `true`.
|
||||
bytes etag = 3 [(require.exactlySize) = 0, (require.exactlySize) = 10];
|
||||
}
|
||||
|
||||
message GetProfileAnonymousRequest {
|
||||
// Contains the data necessary to request a profile.
|
||||
GetProfileRequest request = 1 [(require.present) = true];
|
||||
oneof authentication {
|
||||
// The unidentified access key for the targeted account.
|
||||
bytes unidentified_access_key = 2 [(require.exactlySize) = 16];
|
||||
|
||||
// A group send endorsement token for the targeted account.
|
||||
bytes group_send_token = 3 [(require.nonEmpty) = true];
|
||||
}
|
||||
}
|
||||
|
||||
message AccountInfo {
|
||||
// The account identity key of the targeted account.
|
||||
bytes identity_key = 1;
|
||||
|
||||
// A checksum of the unidentified access key for the targeted account.
|
||||
bytes unidentified_access_key_fingerprint = 2;
|
||||
|
||||
// Whether the account has enabled sealed sender from anyone.
|
||||
bool unrestricted_unidentified_access = 3;
|
||||
|
||||
// A list of the badges ids associated with the account. Metadata to display
|
||||
// badges may be obtained by cross-referencing badge ids with
|
||||
// RemoteConfiguration.GetBadges.
|
||||
repeated string badge_ids = 4;
|
||||
}
|
||||
|
||||
message ProfileResult {
|
||||
// The ciphertext of the requested version of the profile
|
||||
bytes data = 1;
|
||||
|
||||
// The ciphertext of the MobileCoin wallet ID on the profile.
|
||||
bytes payment_address = 2;
|
||||
|
||||
// Information about the targeted account
|
||||
AccountInfo account_info = 3;
|
||||
|
||||
// An entity tag for the profile. This may be used in subsequent requests
|
||||
// for this profile version to optimize bandwidth.
|
||||
//
|
||||
// Note that this hash will not match the expected_data_hash used on
|
||||
// SetProfile for concurrency control.
|
||||
//
|
||||
// Clients may validate that the value has been correctly calculated by
|
||||
// calculating a 10-byte truncated TupleHash256 as follows:
|
||||
//
|
||||
// ```
|
||||
// TupleHash256(S = "ProfileETag/v1", L = 80 bits, tuple = [
|
||||
// data,
|
||||
// payment_address,
|
||||
// account_info.identity_key,
|
||||
// account_info.unidentified_access_key_fingerprint,
|
||||
// account_info.unrestricted_unidentified_access ? 0x01 : 0x00,
|
||||
// uint32BE(count(account_info.badge_ids)),
|
||||
// utf8(id) for each id in sortLexAscendingByUtf8Bytes(account_info.badge_ids),
|
||||
// ])
|
||||
//```
|
||||
//
|
||||
// Absent/empty fields contribute an empty element (not zero bytes omitted):
|
||||
// a missing payment_address is still a present, zero-length tuple element.
|
||||
//
|
||||
// This etag will always exclusively cover the documented fields. If fields
|
||||
// are added in the future, a new etag field must be introduced.
|
||||
bytes etag = 4;
|
||||
}
|
||||
|
||||
message LegacyProfileResult {
|
||||
|
||||
// The ciphertext of the name on the profile.
|
||||
bytes name = 1;
|
||||
// The ciphertext of the description on the profile.
|
||||
bytes about = 2;
|
||||
// The ciphertext of the emoji on the profile.
|
||||
bytes about_emoji = 3;
|
||||
// The cdn0 path of the avatar on the profile.
|
||||
string avatar = 4;
|
||||
// The ciphertext of the phone-number sharing setting on the profile.
|
||||
bytes phone_number_sharing = 5;
|
||||
// The ciphertext of the MobileCoin wallet ID on the profile.
|
||||
bytes payment_address = 6;
|
||||
// Information about the targeted account
|
||||
AccountInfo account_info = 7;
|
||||
}
|
||||
|
||||
|
||||
message GetProfileResponse {
|
||||
oneof response {
|
||||
// The full profile data. The current profile did not match the provided
|
||||
// etag (or no etag was provided).
|
||||
ProfileResult profile = 1;
|
||||
|
||||
// The current profile matched the provided etag. If present, this will always be true.
|
||||
bool etag_matched = 2 [(tag.reason) = "etag_match"];
|
||||
|
||||
errors.NotFound not_found = 3 [(tag.reason) = "not_found"];
|
||||
|
||||
// Will be present if there is no v2 Profile data for this version.
|
||||
//
|
||||
// Because this is a temporary field during the migration, it has the highest
|
||||
// field number without serialization overhead. This is purely aesthetic.
|
||||
LegacyProfileResult legacy_profile = 15 [(tag.reason) = "legacy_profile"];
|
||||
}
|
||||
// next: 4
|
||||
}
|
||||
|
||||
message GetProfileAnonymousResponse {
|
||||
oneof response {
|
||||
// The full profile data. The current profile did not match the provided
|
||||
// etag (or no etag was provided).
|
||||
ProfileResult profile = 1;
|
||||
|
||||
// The current profile matched the provided etag. If present, this will always be true.
|
||||
bool etag_matched = 2 [(tag.reason) = "etag_match"];
|
||||
|
||||
errors.NotFound not_found = 3 [(tag.reason) = "not_found"];
|
||||
errors.FailedUnidentifiedAuthorization failed_unidentified_authorization = 4 [(tag.reason) = "failed_unidentified_authorization"];
|
||||
|
||||
// Will be present if there is no v2 Profile data for this version.
|
||||
//
|
||||
// Because this is a temporary field during the migration, it has the highest
|
||||
// field number without serialization overhead. This is purely aesthetic.
|
||||
LegacyProfileResult profile_v1 = 15 [(tag.reason) = "profile_v1"];
|
||||
}
|
||||
// next: 5
|
||||
}
|
||||
|
||||
message GetExpiringProfileKeyCredentialRequest {
|
||||
// The ACI of the account for which to get a profile key credential.
|
||||
common.ServiceIdentifier account_identifier = 1 [(require.present) = true, (require.identityType) = IDENTITY_TYPE_ACI];
|
||||
// A zkgroup request for a profile key credential.
|
||||
bytes credential_request = 2 [(require.nonEmpty) = true];
|
||||
// The type of credential being requested.
|
||||
CredentialType credential_type = 3 [(require.specified) = true];
|
||||
// The profile version for which to generate a profile key credential.
|
||||
bytes version = 4 [(require.exactlySize) = 32];
|
||||
}
|
||||
|
||||
message GetExpiringProfileKeyCredentialAnonymousRequest {
|
||||
// Contains the data necessary to request an expiring profile key credential.
|
||||
GetExpiringProfileKeyCredentialRequest request = 1 [(require.present) = true];
|
||||
// The unidentified access key for the targeted account.
|
||||
bytes unidentified_access_key = 2 [(require.exactlySize) = 16];
|
||||
}
|
||||
|
||||
message GetExpiringProfileKeyCredentialResult {
|
||||
// A zkgroup credential used by a client to prove that it has the profile key
|
||||
// of a targeted account.
|
||||
bytes profile_key_credential = 1;
|
||||
}
|
||||
|
||||
message GetExpiringProfileKeyCredentialAnonymousResponse {
|
||||
oneof response {
|
||||
GetExpiringProfileKeyCredentialResult result = 1;
|
||||
errors.NotFound not_found = 2 [(tag.reason) = "not_found"];
|
||||
errors.FailedUnidentifiedAuthorization failed_unidentified_authorization = 3 [(tag.reason) = "failed_unidentified_authorization"];
|
||||
}
|
||||
}
|
||||
|
||||
enum CredentialType {
|
||||
CREDENTIAL_TYPE_UNSPECIFIED = 0;
|
||||
CREDENTIAL_TYPE_EXPIRING_PROFILE_KEY = 1;
|
||||
}
|
||||
|
||||
// avatar auth
|
||||
|
||||
message GetAvatarCredentialsRequest {
|
||||
bytes avatar_credentials_request = 1;
|
||||
}
|
||||
|
||||
message GetAvatarCredentialsResponse {
|
||||
oneof response {
|
||||
bytes avatar_credentials = 1;
|
||||
|
||||
// the client must call Accounts.SetZkCredentialKey to call this method
|
||||
errors.FailedPrecondition missing_zk_credential_key = 2 [(tag.reason) = "missing_zk_credential_key"];
|
||||
}
|
||||
}
|
||||
|
||||
message GetAvatarUploadFormRequest {
|
||||
bytes avatar_credentials_presentation = 1;
|
||||
|
||||
// The length of the attachment for the requested upload form. Uploads
|
||||
// performed with this form will be limited to the provided length.
|
||||
uint32 upload_length = 2 [(require.range) = {min: 1, max: 10485760 /* 10 MiB */}];
|
||||
}
|
||||
|
||||
message GetAvatarUploadFormResponse {
|
||||
oneof response {
|
||||
common.S3UploadForm avatar_upload_form = 1;
|
||||
|
||||
errors.FailedZkAuthentication invalid_credentials_presentation = 2 [(tag.reason) = "invalid_credentials_presentation"];
|
||||
}
|
||||
}
|
||||
|
||||
message ExtendAvatarTTLRequest {
|
||||
bytes avatar_credentials_presentation = 1;
|
||||
}
|
||||
|
||||
message ExtendAvatarTTLResponse {
|
||||
oneof response {
|
||||
// The avatar that was extended. May be used as a check against state de-synchronization.
|
||||
string path = 1;
|
||||
errors.FailedZkAuthentication invalid_credentials_presentation = 2 [(tag.reason) = "invalid_credentials_presentation"];
|
||||
// the identity does not have an active avatar
|
||||
errors.NotFound not_found = 3 [(tag.reason) = "no_active_avatar"];
|
||||
}
|
||||
}
|
||||
|
||||
message DeleteAvatarRequest {
|
||||
bytes avatar_credentials_presentation = 1;
|
||||
}
|
||||
|
||||
message DeleteAvatarResponse {
|
||||
oneof response {
|
||||
google.protobuf.Empty success = 1;
|
||||
errors.FailedZkAuthentication invalid_credentials_presentation = 2 [(tag.reason) = "invalid_credentials_presentation"];
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Copyright 2026 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
option java_multiple_files = true;
|
||||
|
||||
package org.signal.chat.remoteconfiguration;
|
||||
|
||||
import "org/signal/chat/common.proto";
|
||||
import "org/signal/chat/require.proto";
|
||||
import "org/signal/chat/tag.proto";
|
||||
|
||||
// Provides remote configuration applicable to the authenticated user
|
||||
service RemoteConfiguration {
|
||||
option (require.auth) = AUTH_ONLY_AUTHENTICATED;
|
||||
|
||||
// Fetches the configuration for the authenticated user. Returned
|
||||
// values are based on the authenticated account and caller's client platform,
|
||||
// which is derived from the "User-Agent" header.
|
||||
rpc GetConfiguration(GetConfigurationRequest) returns (GetConfigurationResponse) {}
|
||||
|
||||
// Returns detailed information for all configured badges, keyed by badge ID.
|
||||
//
|
||||
// Badge descriptions may contain localized strings. Callers should set their
|
||||
// language preferences via an "Accept-Language" header on the request
|
||||
// https://datatracker.ietf.org/doc/html/rfc3282#section-3
|
||||
//
|
||||
// Callers may cache a badges result for up to 1 day before checking (via
|
||||
// etag) if there are any new updates.
|
||||
rpc GetBadges(GetBadgesRequest) returns (GetBadgesResponse) {}
|
||||
}
|
||||
|
||||
message GetConfigurationRequest {
|
||||
// If present, the etag from a prior GetConfigurationResponse. If the
|
||||
// provided etag matches the current configuration etag, the server may elide
|
||||
// the configuration response.
|
||||
bytes etag = 1;
|
||||
}
|
||||
|
||||
message GetConfigurationResponse {
|
||||
oneof response {
|
||||
// The full configuration and corresponding etag.
|
||||
TaggedConfiguration tagged_configuration = 1;
|
||||
|
||||
// The etag in the request matched the current configuration etag.
|
||||
bool etag_matched = 2 [(tag.reason) = "etag_match"];
|
||||
}
|
||||
}
|
||||
|
||||
message Configuration {
|
||||
// A map of namespaced configuration keys to their resolved values. All
|
||||
// configuration values are represented as strings. boolean values are
|
||||
// represented as the strings "true" or "false".
|
||||
map<string, string> configuration = 1;
|
||||
}
|
||||
|
||||
message TaggedConfiguration {
|
||||
Configuration configuration = 1;
|
||||
|
||||
// An entity tag for `configuration`. This may be supplied in a
|
||||
// subsequent request to optimize bandwidth when the configuration has not
|
||||
// changed.
|
||||
bytes etag = 2;
|
||||
}
|
||||
|
||||
message GetBadgesRequest {
|
||||
// If present, the etag from a prior GetBadgesResponse. If the provided etag
|
||||
// matches the current badge etag, the server may elide the badge response.
|
||||
bytes etag = 1;
|
||||
}
|
||||
|
||||
message GetBadgesResponse {
|
||||
oneof response {
|
||||
// The full set of badges and corresponding etag.
|
||||
TaggedBadges tagged_badges = 1;
|
||||
|
||||
// The etag in the request matched the current badge etag.
|
||||
bool etag_matched = 2 [(tag.reason) = "etag_match"];
|
||||
}
|
||||
}
|
||||
|
||||
message Badges {
|
||||
// A map of badge ID to the detailed information for that badge.
|
||||
map<string, common.Badge> badges = 1;
|
||||
}
|
||||
|
||||
message TaggedBadges {
|
||||
Badges badges = 1;
|
||||
|
||||
// An entity tag for `badges`. This may be supplied in a subsequent request
|
||||
// to optimize bandwidth when the set of badges has not changed.
|
||||
bytes etag = 2;
|
||||
}
|
||||
258
pkg/signalmeow/protobuf/org/signal/chat/require.proto
Normal file
258
pkg/signalmeow/protobuf/org/signal/chat/require.proto
Normal file
|
|
@ -0,0 +1,258 @@
|
|||
/*
|
||||
* Copyright 2023 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
option java_multiple_files = true;
|
||||
|
||||
package org.signal.chat.require;
|
||||
|
||||
import "google/protobuf/descriptor.proto";
|
||||
|
||||
extend google.protobuf.FieldOptions {
|
||||
/*
|
||||
* Requires a field to have content of non-zero size/length.
|
||||
* Applies to both `optional` and regular fields, i.e. if the field is not set
|
||||
* or has a default value, it's considered to be empty. This does not apply
|
||||
* to fields that are contained in a `oneof`.
|
||||
*
|
||||
* ```
|
||||
* import "org/signal/chat/require.proto";
|
||||
*
|
||||
* message Data {
|
||||
* string nonEmptyString = 1 [(require.nonEmpty) = true];
|
||||
* bytes nonEmptyBytes = 2 [(require.nonEmpty) = true];
|
||||
* optional string nonEmptyStringOptional = 3 [(require.nonEmpty) = true];
|
||||
* optional bytes nonEmptyBytesOptional = 4 [(require.nonEmpty) = true];
|
||||
* repeated string nonEmptyList = 5 [(require.nonEmpty) = true];
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* Applicable to fields of type `string`, `byte`, and `repeated` fields.
|
||||
*/
|
||||
optional bool nonEmpty = 70001;
|
||||
|
||||
/*
|
||||
* Requires a enum field to have value with an index greater than zero.
|
||||
* Applies to both `optional` and regular fields, i.e. if the field is not set or has a default value,
|
||||
* its index will be <= 0.
|
||||
*
|
||||
* ```
|
||||
* import "org/signal/chat/require.proto";
|
||||
*
|
||||
* message Data {
|
||||
* Color color = 1 [(require.specified) = true];
|
||||
* }
|
||||
*
|
||||
* enum Color {
|
||||
* COLOR_UNSPECIFIED = 0;
|
||||
* COLOR_RED = 1;
|
||||
* COLOR_GREEN = 2;
|
||||
* COLOR_BLUE = 3;
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
optional bool specified = 70002;
|
||||
|
||||
/*
|
||||
* Requires a size/length of a field to be within certain boundaries.
|
||||
* Applies to both `optional` and regular fields, i.e. if the field is not set
|
||||
* or has a default value, its size considered to be zero. However, if the
|
||||
* field is contained in a `oneof` and is not set, this annotation does not
|
||||
* apply.
|
||||
*
|
||||
* ```
|
||||
* import "org/signal/chat/require.proto";
|
||||
*
|
||||
* message Data {
|
||||
*
|
||||
* string name = 1 [(require.size) = {min: 3, max: 8}];
|
||||
*
|
||||
* optional string address = 2 [(require.size) = {min: 3, max: 8}];
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* Applicable to fields of type `string`, `byte`, and `repeated` fields.
|
||||
*/
|
||||
optional SizeConstraint size = 70003;
|
||||
|
||||
/*
|
||||
* Requires a size/length of a field to be within certain boundaries.
|
||||
* Applies to both `optional` and regular fields, i.e. if the field is not set
|
||||
* or has a default value, its size considered to be zero. However, if the
|
||||
* field is contained in a `oneof` and is not set, this annotation does not
|
||||
* apply.
|
||||
*
|
||||
* ```
|
||||
* import "org/signal/chat/require.proto";
|
||||
*
|
||||
* message Data {
|
||||
*
|
||||
* string zip = 1 [(require.exactlySize) = 5];
|
||||
*
|
||||
* optional string exactlySizeVariants = 2 [(require.exactlySize) = 2, (require.exactlySize) = 4];
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* Applicable to fields of type `string`, `byte`, and `repeated` fields.
|
||||
*/
|
||||
repeated uint32 exactlySize = 70004;
|
||||
|
||||
/*
|
||||
* Requires a value of a string field to be a valid E164-normalized phone number.
|
||||
* If the field is `optional`, this check allows a value to be not set.
|
||||
*
|
||||
* ```
|
||||
* import "org/signal/chat/require.proto";
|
||||
*
|
||||
* message Data {
|
||||
* string number = 1 [(require.e164)];
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
optional bool e164 = 70005;
|
||||
|
||||
/*
|
||||
* Requires an integer value to be within a certain range. The range boundaries are specified
|
||||
* with the values of type `int32`, which should be enough for all practical purposes.
|
||||
*
|
||||
* If the field is `optional`, this check allows a value to be not set.
|
||||
*
|
||||
* ```
|
||||
* import "org/signal/chat/require.proto";
|
||||
*
|
||||
* message Data {
|
||||
* int32 byte = 1 [(require.range) = {min: -128, max: 127}];
|
||||
* uint32 unsignedByte = 2 [(require.range).max = 255];
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
optional ValueRangeConstraint range = 70006;
|
||||
|
||||
/*
|
||||
* Require a value of a message field to be present.
|
||||
*
|
||||
* Applies to both `optional` and regular fields (both of which have explicit
|
||||
* presence for the message type anyways). This does not apply to fields that
|
||||
* are contained in a `oneof`.
|
||||
*
|
||||
* ```
|
||||
* import "org/signal/chat/require.proto";
|
||||
* message Data {
|
||||
* message MyMessage {}
|
||||
* MyMessage myMessage = 1 [(require.present) = true];
|
||||
* }
|
||||
*````
|
||||
*/
|
||||
optional bool present = 70007;
|
||||
|
||||
/*
|
||||
* Requires a value of a string field to be a valid base64 URL string. The
|
||||
* string may be padded or unpadded. If the field is `optional`, this check
|
||||
* allows a value to be not set.
|
||||
*
|
||||
* ```
|
||||
* import "org/signal/chat/require.proto";
|
||||
*
|
||||
* message Data {
|
||||
* string myString = 1 [(require.base64url) = true];
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
optional bool base64url = 70008;
|
||||
|
||||
/*
|
||||
* Requires a common.ServiceIdentifier field to have its IdentityType
|
||||
* be the given type (`aci` or `pni`).
|
||||
*
|
||||
* ```
|
||||
* import "org/signal/chat/require.proto";
|
||||
* import "org/signal/chat/common.proto";
|
||||
*
|
||||
* message Data {
|
||||
* common.ServiceIdentifier accountIdentifier = 1 [(require.identityType) = IDENTITY_TYPE_ACI];
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
optional IdentityType identityType = 70009;
|
||||
|
||||
/*
|
||||
* Applies element-wise constraints to the elements of a `repeated` field.
|
||||
* Top-level `require.*` annotations on a `repeated` field constrain the
|
||||
* collection itself (e.g. element count), `each` constrains the
|
||||
* individual elements.
|
||||
*
|
||||
* ```
|
||||
* import "org/signal/chat/require.proto";
|
||||
*
|
||||
* message Data {
|
||||
* // 1-20 username hashes, each exactly 32 bytes
|
||||
* repeated bytes username_hashes = 1 [
|
||||
* (require.size) = {min: 1, max: 20},
|
||||
* (require.each) = { exactlySize: 32 }
|
||||
* ];
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* Applicable only to `repeated` fields.
|
||||
*/
|
||||
optional ElementConstraint each = 70010;
|
||||
|
||||
// next 70011
|
||||
}
|
||||
|
||||
message ElementConstraint {
|
||||
optional bool nonEmpty = 1;
|
||||
optional SizeConstraint size = 2;
|
||||
repeated uint32 exactlySize = 3;
|
||||
optional bool e164 = 4;
|
||||
optional bool base64url = 5;
|
||||
optional ValueRangeConstraint range = 6;
|
||||
optional IdentityType identityType = 7;
|
||||
optional bool specified = 8;
|
||||
}
|
||||
|
||||
message SizeConstraint {
|
||||
optional uint32 min = 1;
|
||||
optional uint32 max = 2;
|
||||
}
|
||||
|
||||
message ValueRangeConstraint {
|
||||
optional int64 min = 1;
|
||||
optional int64 max = 2;
|
||||
}
|
||||
|
||||
extend google.protobuf.ServiceOptions {
|
||||
/*
|
||||
* Indicates that all methods in a given service require a certain kind of authentication.
|
||||
*
|
||||
* ```
|
||||
* import "org/signal/chat/require.proto";
|
||||
*
|
||||
* service AuthService {
|
||||
* option (require.auth) = AUTH_ONLY_AUTHENTICATED;
|
||||
*
|
||||
* rpc AuthenticatedMethod (google.protobuf.Empty) returns (google.protobuf.Empty) {}
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
optional Auth auth = 71001;
|
||||
}
|
||||
|
||||
enum Auth {
|
||||
AUTH_UNSPECIFIED = 0;
|
||||
AUTH_ONLY_AUTHENTICATED = 1;
|
||||
AUTH_ONLY_ANONYMOUS = 2;
|
||||
}
|
||||
|
||||
// This is duplicated from common.proto because:
|
||||
//
|
||||
// 1. importing would be a circular dependency
|
||||
// 2. the canonical declaration belongs there
|
||||
enum IdentityType {
|
||||
IDENTITY_TYPE_UNSPECIFIED = 0;
|
||||
IDENTITY_TYPE_ACI = 1;
|
||||
IDENTITY_TYPE_PNI = 2;
|
||||
}
|
||||
441
pkg/signalmeow/protobuf/org/signal/chat/subscriptions.proto
Normal file
441
pkg/signalmeow/protobuf/org/signal/chat/subscriptions.proto
Normal file
|
|
@ -0,0 +1,441 @@
|
|||
/*
|
||||
* Copyright 2026 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
option java_multiple_files = true;
|
||||
|
||||
package org.signal.chat.purchase;
|
||||
|
||||
import "google/protobuf/empty.proto";
|
||||
import "org/signal/chat/common.proto";
|
||||
import "org/signal/chat/require.proto";
|
||||
import "org/signal/chat/errors.proto";
|
||||
import "org/signal/chat/tag.proto";
|
||||
|
||||
// Service for creating donation subscriptions
|
||||
//
|
||||
// Configuration for subscription levels can be found in ProductConfiguration.
|
||||
service Subscriptions {
|
||||
option (require.auth) = AUTH_ONLY_ANONYMOUS;
|
||||
// Creates a subscriber record if it does not exist, otherwise refreshes its last access time.
|
||||
|
||||
// Subscribers MUST periodically hit this endpoint to update the access time on the subscription record. Subscribers
|
||||
// SHOULD attempt to make an update call approximately every 3 days. Not accessing this endpoint for an extended
|
||||
// period of time will result in the subscription being canceled.
|
||||
rpc UpdateSubscriber(UpdateSubscriberRequest) returns (UpdateSubscriberResponse) {}
|
||||
|
||||
// Cancels any current subscription at the end of the current subscription period.
|
||||
//
|
||||
// Note: Apple IAP subscriptions do not support server-side cancellation, so this method should only be called after
|
||||
// cancelling a subscription from storekit to keep server data up to date.
|
||||
rpc DeleteSubscriber(DeleteSubscriberRequest) returns (DeleteSubscriberResponse) {}
|
||||
|
||||
// Returns a client secret that can be used to set up a new payment method with the payment processor.
|
||||
rpc CreatePaymentMethod(CreatePaymentMethodRequest) returns (CreatePaymentMethodResponse) {}
|
||||
|
||||
// Returns a PayPal billing agreement approval URL and token that can be used to set up PayPal as a payment method.
|
||||
rpc CreatePayPalPaymentMethod(CreatePayPalPaymentMethodRequest) returns (CreatePayPalPaymentMethodResponse) {}
|
||||
|
||||
// Sets the default payment method for a subscriber.
|
||||
rpc SetDefaultPaymentMethod(SetDefaultPaymentMethodRequest) returns (SetDefaultPaymentMethodResponse) {}
|
||||
|
||||
// Sets the subscription level and currency for a subscriber.
|
||||
rpc SetSubscriptionLevel(SetSubscriptionLevelRequest) returns (SetSubscriptionLevelResponse) {}
|
||||
|
||||
// Returns information about the current subscription associated with the provided subscriberId if one exists.
|
||||
//
|
||||
// Although it uses [Stripe's values](https://stripe.com/docs/billing/subscriptions/overview#subscription-statuses),
|
||||
// the status field in the response is generic, with [Braintree-specific values](https://developer.paypal.com/braintree/docs/guides/recurring-billing/overview#subscription-statuses) mapped
|
||||
// to Stripe's. Since we don't support trials or unpaid subscriptions, the associated statuses will never be returned
|
||||
// by the API.
|
||||
rpc GetSubscriptionInformation(GetSubscriptionInformationRequest) returns (GetSubscriptionInformationResponse) {}
|
||||
|
||||
// Create a receipt from a valid payment invoice that can be used to obtain an entitlement
|
||||
//
|
||||
// This request is repeatable so long as the ReceiptCredentialRequest remains the same. Clients should use the same
|
||||
// ReceiptCredentialRequest value until they attempt to redeem the resulting ReceiptCredentialPresentation. After
|
||||
// this point, the ReceiptCredentialRequest MUST NOT be reused or you may not be able to redeem a valid payment
|
||||
// invoice. Clients SHOULD retry requests at this endpoint with the same ReceiptCredentialRequest value until
|
||||
// receiving a response. After receiving a response, clients should then compute the ReceiptCredentialPresentation
|
||||
// and redeem it at the receipt redemption endpoint. Once the first attempt is made there, the same
|
||||
// ReceiptCredentialRequest MUST NOT be used again to request receipt credentials.
|
||||
//
|
||||
// Note that you may in fact redeem TWO or more invoices for the same ReceiptCredentialRequest while retrying this
|
||||
// operation if a later invoice gets paid while you are retrying. However, the returned receipt is always for the
|
||||
// latest invoice, so it will have the latest expiration possible and no entitlement time will be lost. The important
|
||||
// thing is not to reuse ReceiptCredentialRequest after you have started attempting to redeem the associated
|
||||
// ReceiptCredentialPresentation. Then you may produce a ReceiptCredentialPresentation for a later invoice that
|
||||
// cannot be redeemed.
|
||||
//
|
||||
// Clients MUST validate that the generated receipt credential's level and expiration matches their expectations.
|
||||
rpc GetReceiptCredentials(GetReceiptCredentialsRequest) returns (GetReceiptCredentialsResponse) {}
|
||||
|
||||
// Set a token that represents an IAP subscription made with App Store/Google Play Billing.
|
||||
//
|
||||
// To set up an App Store subscription:
|
||||
// 1. Create a subscriber with UpdateSubscriber (you must regularly refresh this subscriber)
|
||||
// 2. [Create a subscription](https://developer.apple.com/documentation/storekit/in-app_purchase/) with the App Store
|
||||
// directly via StoreKit and obtain a originalTransactionId.
|
||||
// 3. Call this RPC with the originalTransactionId
|
||||
// 4. Obtain a receipt via GetReceiptCredentials which can then be used to obtain the
|
||||
// entitlement
|
||||
//
|
||||
// Play Billing: Set a purchaseToken that represents an IAP subscription made with Google Play Billing.
|
||||
//
|
||||
// To set up a subscription with Google Play Billing:
|
||||
// 1. Create a subscriber with UpdateSubscriber (you must regularly refresh this subscriber)
|
||||
// 2. [Create a subscription](https://developer.android.com/google/play/billing/integrate) with Google Play Billing
|
||||
// directly and obtain a purchaseToken. Do not [acknowledge](https://developer.android.com/google/play/billing/integrate#subscriptions)
|
||||
// the purchaseToken.
|
||||
// 3. Call this RPC with the purchaseToken
|
||||
// 4. Obtain a receipt via GetReceiptCredentials which can then be used to obtain the
|
||||
// entitlement
|
||||
//
|
||||
// After calling this method, the payment is confirmed. Callers must durably store their subscriberId before calling
|
||||
// this method to ensure their payment is tracked.
|
||||
//
|
||||
// Once a purchaseToken to is posted to a subscriberId, the same subscriberId must not be used with another payment
|
||||
// method. A different playbilling purchaseToken can be posted to the same subscriberId, in this case the subscription
|
||||
// associated with the old purchaseToken will be cancelled.
|
||||
rpc SetIapSubscription(SetIapSubscriptionRequest) returns (SetIapSubscriptionResponse) {}
|
||||
|
||||
// Returns a localized bank mandate for the specified bank transfer type
|
||||
rpc GetBankMandate(GetBankMandateRequest) returns (GetBankMandateResponse) {}
|
||||
}
|
||||
|
||||
message UpdateSubscriberRequest {
|
||||
bytes subscriber_id = 1 [(require.exactlySize) = 32];
|
||||
// A libsignal DonationPermit from rpc Donations.CreateDonationPermit.
|
||||
// Not required if the subscriber already exists.
|
||||
bytes donation_permit = 2;
|
||||
}
|
||||
|
||||
message UpdateSubscriberResponse {
|
||||
oneof response {
|
||||
google.protobuf.Empty success = 1;
|
||||
// subscriberId authentication failure
|
||||
errors.FailedUnidentifiedAuthorization subscriber_id_mismatch = 2 [(tag.reason) = "subscriber_id_mismatch"];
|
||||
// The donation permit was expired or already spent
|
||||
errors.FailedZkAuthentication permit_rejected = 3 [(tag.reason) = "permit_rejected"];
|
||||
}
|
||||
}
|
||||
|
||||
message DeleteSubscriberRequest {
|
||||
bytes subscriberId = 1 [(require.exactlySize) = 32];
|
||||
}
|
||||
|
||||
message DeleteSubscriberResponse {
|
||||
oneof response {
|
||||
google.protobuf.Empty success = 1;
|
||||
errors.NotFound subscriber_not_found = 2 [(tag.reason) = "subscriber_not_found"];
|
||||
// The associated subscription is not a type that can be cancelled by the server. Cancel client-side, and then retry.
|
||||
errors.FailedPrecondition cannot_cancel_subscription = 3 [(tag.reason) = "cannot_cancel_subscription"];
|
||||
}
|
||||
}
|
||||
|
||||
enum PaymentProvider {
|
||||
PAYMENT_PROVIDER_UNKNOWN = 0;
|
||||
PAYMENT_PROVIDER_STRIPE = 1;
|
||||
PAYMENT_PROVIDER_BRAINTREE = 2;
|
||||
PAYMENT_PROVIDER_GOOGLE_PLAY_BILLING = 3;
|
||||
PAYMENT_PROVIDER_APPLE_APP_STORE = 4;
|
||||
}
|
||||
|
||||
enum PaymentMethod {
|
||||
PAYMENT_METHOD_UNKNOWN = 0;
|
||||
// A credit card or debit card, including those from Apple Pay and Google Pay
|
||||
PAYMENT_METHOD_CARD = 1;
|
||||
// A SEPA debit account
|
||||
PAYMENT_METHOD_SEPA_DEBIT = 2;
|
||||
// An iDEAL account
|
||||
PAYMENT_METHOD_IDEAL = 3;
|
||||
// A PayPal account
|
||||
PAYMENT_METHOD_PAYPAL = 4;
|
||||
PAYMENT_METHOD_GOOGLE_PLAY_BILLING = 5;
|
||||
PAYMENT_METHOD_APPLE_APP_STORE = 6;
|
||||
}
|
||||
|
||||
enum SubscriptionStatus {
|
||||
SUBSCRIPTION_STATUS_UNKNOWN = 0;
|
||||
// The subscription is in good standing and the most recent payment was successful.
|
||||
SUBSCRIPTION_STATUS_ACTIVE = 1;
|
||||
// Payment failed when creating the subscription, or the subscription's start date is in the future.
|
||||
SUBSCRIPTION_STATUS_INCOMPLETE = 2;
|
||||
// Payment on the latest renewal failed but there are processor retries left, or payment wasn't attempted.
|
||||
SUBSCRIPTION_STATUS_PAST_DUE = 3;
|
||||
// The subscription has been canceled.
|
||||
SUBSCRIPTION_STATUS_CANCELED = 4;
|
||||
// The latest renewal hasn't been paid but the subscription remains in place.
|
||||
SUBSCRIPTION_STATUS_UNPAID = 5;
|
||||
}
|
||||
|
||||
message CreatePaymentMethodRequest {
|
||||
// Only PAYMENT_METHOD_CARD, PAYMENT_METHOD_SEPA_DEBIT, and PAYMENT_METHOD_IDEAL are supported;
|
||||
// other values will result in an INVALID_ARGUMENT error.
|
||||
bytes subscriber_id = 1 [(require.exactlySize) = 32];
|
||||
PaymentMethod payment_method = 2 [(require.specified) = true];
|
||||
// a libsignal DonationPermit from rpc Donations.CreateDonationPermit
|
||||
bytes donation_permit = 3 [(require.nonEmpty) = true];
|
||||
}
|
||||
|
||||
message CreatePaymentMethodResponse {
|
||||
message CreatePaymentMethodResult {
|
||||
string clientSecret = 1;
|
||||
PaymentProvider paymentProvider = 2;
|
||||
}
|
||||
|
||||
oneof response {
|
||||
CreatePaymentMethodResult result = 1;
|
||||
errors.NotFound subscriber_not_found = 2 [(tag.reason) = "subscriber_not_found"];
|
||||
// subscriberId authentication failure
|
||||
errors.FailedUnidentifiedAuthorization subscriber_id_mismatch = 3 [(tag.reason) = "subscriber_id_mismatch"];
|
||||
// New payment processor does not match existing processor associated with the subscription
|
||||
errors.FailedPrecondition subscription_processor_conflict = 4 [(tag.reason) = "subscription_processor_conflict"];
|
||||
// The donation permit was expired or already spent
|
||||
errors.FailedZkAuthentication permit_rejected = 5 [(tag.reason) = "permit_rejected"];
|
||||
}
|
||||
}
|
||||
|
||||
message CreatePayPalPaymentMethodRequest {
|
||||
bytes subscriberId = 1 [(require.exactlySize) = 32];
|
||||
// a callback URL (e.g. an in-client URL handler) for when the user approved the payment
|
||||
string returnUrl = 2;
|
||||
// a callback URL (e.g. an in-client URL handler) for when the user did not approve the payment
|
||||
string cancelUrl = 3;
|
||||
}
|
||||
|
||||
message CreatePayPalPaymentMethodResponse {
|
||||
message CreatePayPalPaymentMethodResult {
|
||||
// a URL to open where the user may approve the payment
|
||||
string approvalUrl = 1;
|
||||
// an opaque PayPal payment identifier to use with SetDefaultPaymentMethodRequest
|
||||
string token = 2;
|
||||
}
|
||||
|
||||
oneof response {
|
||||
CreatePayPalPaymentMethodResult result = 1;
|
||||
errors.NotFound subscriber_not_found = 2 [(tag.reason) = "subscriber_not_found"];
|
||||
// subscriberId authentication failure
|
||||
errors.FailedUnidentifiedAuthorization subscriber_id_mismatch = 3 [(tag.reason) = "subscriber_id_mismatch"];
|
||||
// New payment processor does not match existing processor associated with the subscription
|
||||
errors.FailedPrecondition subscription_processor_conflict = 4 [(tag.reason) = "subscription_processor_conflict"];
|
||||
}
|
||||
}
|
||||
|
||||
message SetDefaultPaymentMethodRequest {
|
||||
message StripePaymentMethod {
|
||||
string paymentMethodToken = 1 [(require.nonEmpty) = true];
|
||||
}
|
||||
message BraintreePaymentMethod {
|
||||
string paymentMethodToken = 1 [(require.nonEmpty) = true];
|
||||
}
|
||||
message SepaPaymentMethod {
|
||||
string setupIntentId = 1 [(require.nonEmpty) = true];
|
||||
}
|
||||
|
||||
bytes subscriberId = 1 [(require.exactlySize) = 32];
|
||||
oneof request {
|
||||
StripePaymentMethod stripe = 2;
|
||||
BraintreePaymentMethod braintree = 3;
|
||||
SepaPaymentMethod sepa = 4;
|
||||
}
|
||||
}
|
||||
|
||||
message SetDefaultPaymentMethodResponse {
|
||||
oneof response {
|
||||
google.protobuf.Empty success = 1;
|
||||
errors.NotFound subscriber_not_found = 2 [(tag.reason) = "subscriber_not_found"];
|
||||
// subscriberId authentication failure
|
||||
errors.FailedUnidentifiedAuthorization subscriber_id_mismatch = 3 [(tag.reason) = "subscriber_id_mismatch"];
|
||||
errors.FailedPrecondition payment_method_not_set_up = 4 [(tag.reason) = "payment_method_not_set_up"];
|
||||
// Payment processor does not match existing processor associated with the subscription
|
||||
errors.FailedPrecondition subscription_processor_conflict = 5 [(tag.reason) = "subscription_processor_conflict"];
|
||||
}
|
||||
}
|
||||
|
||||
message SetSubscriptionLevelRequest {
|
||||
bytes subscriberId = 1 [(require.exactlySize) = 32];
|
||||
uint64 level = 2;
|
||||
string currency = 3;
|
||||
string idempotencyKey = 4;
|
||||
}
|
||||
|
||||
// Information about a charge failure.
|
||||
|
||||
// Meaningfully interpreting chargeFailure response fields requires inspecting the processor field first.
|
||||
//
|
||||
// For Stripe, code will be one of the [codes defined here](https://stripe.com/docs/api/charges/object#charge_object-failure_code),
|
||||
// while message [may contain a further textual description](https://stripe.com/docs/api/charges/object#charge_object-failure_message).
|
||||
// The outcome fields are optional, but present values will directly map to Stripe [response properties](https://stripe.com/docs/api/charges/object#charge_object-outcome-network_status)
|
||||
//
|
||||
// For Braintree, the outcome fields will be null. The code and message will contain one of
|
||||
// - a processor decline code (as a string) in code, and associated text in message, as defined this [table](https://developer.paypal.com/braintree/docs/reference/general/processor-responses/authorization-responses)
|
||||
// - `gateway` in code, with a [reason](https://developer.paypal.com/braintree/articles/control-panel/transactions/gateway-rejections) in message
|
||||
// - `code` = "unknown", message = "unknown"
|
||||
//
|
||||
// IAP payment processors will never include charge failure information, and detailed order information should be
|
||||
// retrieved from the payment processor directly
|
||||
message ChargeFailure {
|
||||
PaymentProvider processor = 1;
|
||||
// See [Stripe failure codes](https://stripe.com/docs/api/charges/object#charge_object-failure_code) or
|
||||
// [Braintree decline codes](https://developer.paypal.com/braintree/docs/reference/general/processor-responses/authorization-responses#decline-codes)
|
||||
// depending on which processor was used
|
||||
string code = 2;
|
||||
// See [Stripe failure codes](https://stripe.com/docs/api/charges/object#charge_object-failure_code) or
|
||||
// [Braintree decline codes](https://developer.paypal.com/braintree/docs/reference/general/processor-responses/authorization-responses#decline-codes)
|
||||
// depending on which processor was used
|
||||
string message = 3;
|
||||
// See [Outcome Network Status](https://stripe.com/docs/api/charges/object#charge_object-outcome-network_status)
|
||||
optional string outcome_network_status = 4;
|
||||
// See [Outcome Reason](https://stripe.com/docs/api/charges/object#charge_object-outcome-reason)
|
||||
optional string outcome_reason = 5;
|
||||
// See [Outcome Type](https://stripe.com/docs/api/charges/object#charge_object-outcome-type)
|
||||
optional string outcome_type = 6;
|
||||
}
|
||||
|
||||
message PaymentRequired {
|
||||
optional ChargeFailure charge_failure = 1;
|
||||
}
|
||||
|
||||
message SetSubscriptionLevelResponse {
|
||||
message SetSubscriptionLevelResult {
|
||||
uint64 level = 1;
|
||||
}
|
||||
|
||||
oneof response {
|
||||
SetSubscriptionLevelResult success = 1;
|
||||
errors.NotFound subscriber_not_found = 2 [(tag.reason) = "subscriber_not_found"];
|
||||
// subscriberId authentication failure
|
||||
errors.FailedUnidentifiedAuthorization subscriber_id_mismatch = 3 [(tag.reason) = "subscriber_id_mismatch"];
|
||||
// New payment processor does not match existing processor associated with the subscription
|
||||
errors.FailedPrecondition subscription_processor_conflict = 4 [(tag.reason) = "subscription_processor_conflict"];
|
||||
errors.FailedPrecondition payment_method_not_set_up = 5 [(tag.reason) = "payment_method_not_set_up"];
|
||||
// The payment processor does not support this operation
|
||||
errors.FailedPrecondition unsupported_operation = 6 [(tag.reason) = "unsupported_operation"];
|
||||
// The requested level was invalid
|
||||
errors.FailedPrecondition unsupported_level = 7 [(tag.reason) = "unsupported_level"];
|
||||
// The requested currency was invalid
|
||||
errors.FailedPrecondition unsupported_currency = 8 [(tag.reason) = "unsupported_currency"];
|
||||
// The card could not be charged
|
||||
errors.FailedPrecondition payment_requires_action = 9 [(tag.reason) = "payment_requires_action"];
|
||||
// Cannot transition from existing level to the requested level
|
||||
errors.FailedPrecondition invalid_level_transition = 10 [(tag.reason) = "invalid_level_transition"];
|
||||
// The idempotency key was invalid or re-used with a modified request
|
||||
errors.FailedPrecondition invalid_idempotency_key = 11 [(tag.reason) = "invalid_idempotency_key"];
|
||||
// The payment failed; see charge failure details
|
||||
ChargeFailure charge_failure = 12 [(tag.reason) = "charge_failure"];
|
||||
}
|
||||
}
|
||||
|
||||
message SetIapSubscriptionRequest {
|
||||
message AppStorePurchase {
|
||||
string original_transaction_id = 1 [(require.nonEmpty) = true];
|
||||
}
|
||||
message PlayBillingPurchase {
|
||||
string purchase_token = 1 [(require.nonEmpty) = true];
|
||||
}
|
||||
|
||||
bytes subscriberId = 1 [(require.exactlySize) = 32];
|
||||
oneof request {
|
||||
AppStorePurchase app_store = 2;
|
||||
PlayBillingPurchase play_billing = 3;
|
||||
}
|
||||
}
|
||||
|
||||
message SetIapSubscriptionResponse {
|
||||
message SetIapSubscriptionResult {
|
||||
uint64 level = 1;
|
||||
}
|
||||
|
||||
oneof response {
|
||||
SetIapSubscriptionResult success = 1;
|
||||
errors.NotFound subscriber_not_found = 2 [(tag.reason) = "subscriber_not_found"];
|
||||
// subscriberId authentication failure
|
||||
errors.FailedUnidentifiedAuthorization subscriber_id_mismatch = 3 [(tag.reason) = "subscriber_id_mismatch"];
|
||||
// New payment processor does not match existing processor associated with the subscription
|
||||
errors.FailedPrecondition subscription_processor_conflict = 4 [(tag.reason) = "subscription_processor_conflict"];
|
||||
errors.FailedPrecondition payment_required = 5 [(tag.reason) = "payment_required"];
|
||||
errors.FailedPrecondition invalid_transaction = 6 [(tag.reason) = "invalid_transaction"];
|
||||
}
|
||||
}
|
||||
|
||||
message GetReceiptCredentialsRequest {
|
||||
bytes subscriberId = 1 [(require.exactlySize) = 32];
|
||||
bytes receiptCredentialRequest = 2 [(require.exactlySize) = 97];
|
||||
}
|
||||
|
||||
message GetReceiptCredentialsResponse {
|
||||
message GetReceiptCredentialsResult {
|
||||
bytes receiptCredentialResponse = 1;
|
||||
}
|
||||
|
||||
oneof response {
|
||||
GetReceiptCredentialsResult success = 1;
|
||||
errors.NotFound subscriber_not_found = 2 [(tag.reason) = "subscriber_not_found"];
|
||||
// subscriberId authentication failure
|
||||
errors.FailedUnidentifiedAuthorization subscriber_id_mismatch = 3 [(tag.reason) = "subscriber_id_mismatch"];
|
||||
// No invoice has been issued for this subscription OR invoice is in 'draft' or 'open' state
|
||||
errors.FailedPrecondition no_paid_invoice = 4 [(tag.reason) = "no_paid_invoice"];
|
||||
// Invoice is in any state other than 'draft', 'open', or 'paid'; Charge failure details may be present
|
||||
PaymentRequired payment_required = 5 [(tag.reason) = "payment_required"];
|
||||
// Latest paid receipt on subscription was already redeemed for a receipt credential but with a different GetReceiptCredentialRequest
|
||||
errors.FailedPrecondition already_redeemed = 6 [(tag.reason) = "already_redeemed"];
|
||||
}
|
||||
}
|
||||
|
||||
message GetSubscriptionInformationRequest {
|
||||
bytes subscriberId = 1 [(require.exactlySize) = 32];
|
||||
}
|
||||
|
||||
message GetSubscriptionInformationResponse {
|
||||
message Subscription {
|
||||
// The subscription level
|
||||
uint64 level = 1;
|
||||
// If present, UNIX Epoch Timestamp in seconds, can be used to calculate next billing date.
|
||||
optional uint64 billing_cycle_anchor = 2;
|
||||
// UNIX Epoch Timestamp in seconds, when the current subscription period ends
|
||||
uint64 end_of_current_period = 3;
|
||||
// Whether there is a currently active subscription
|
||||
bool active = 4;
|
||||
// If true, an active subscription will not auto-renew at the end of the current period
|
||||
bool cancel_at_period_end = 5;
|
||||
// A three-letter ISO 4217 currency code for currency used in the subscription
|
||||
string currency = 6;
|
||||
// The amount paid for the subscription in the currency's smallest unit
|
||||
uint64 amount = 7;
|
||||
// The subscription's status, mapped to Stripe's statuses. trialing will never be returned
|
||||
SubscriptionStatus status = 8;
|
||||
// The payment provider associated with the subscription
|
||||
PaymentProvider processor = 9;
|
||||
// The payment method associated with the subscription
|
||||
PaymentMethod payment_method = 10;
|
||||
// Whether the latest charge for the subscription is in a non-terminal state
|
||||
bool payment_processing = 11;
|
||||
// if present, contains information that may be interpreted to help the user fix a failure
|
||||
optional ChargeFailure charge_failure = 12;
|
||||
}
|
||||
|
||||
oneof response {
|
||||
Subscription success = 1;
|
||||
google.protobuf.Empty no_subscription = 2;
|
||||
errors.NotFound subscriber_not_found = 3 [(tag.reason) = "subscriber_not_found"];
|
||||
// subscriberId authentication failure
|
||||
errors.FailedUnidentifiedAuthorization subscriber_id_mismatch = 4 [(tag.reason) = "subscriber_id_mismatch"];
|
||||
}
|
||||
}
|
||||
|
||||
enum BankTransferType {
|
||||
BANK_TRANSFER_TYPE_UNKNOWN = 0;
|
||||
BANK_TRANSFER_TYPE_SEPA_DEBIT = 1;
|
||||
}
|
||||
|
||||
message GetBankMandateRequest {
|
||||
BankTransferType bank_transfer_type = 1 [(require.specified) = true];
|
||||
}
|
||||
|
||||
message GetBankMandateResponse {
|
||||
string mandate = 1;
|
||||
}
|
||||
38
pkg/signalmeow/protobuf/org/signal/chat/tag.proto
Normal file
38
pkg/signalmeow/protobuf/org/signal/chat/tag.proto
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright 2025 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
option java_multiple_files = true;
|
||||
|
||||
package org.signal.chat.tag;
|
||||
|
||||
import "google/protobuf/descriptor.proto";
|
||||
|
||||
extend google.protobuf.FieldOptions {
|
||||
// Indicate that a message which includes this field (directly or indirectly)
|
||||
// was generated for a particular reason.
|
||||
//
|
||||
// ```
|
||||
// import "org/signal/chat/tag.proto"
|
||||
//
|
||||
// message LookupThingResponse {
|
||||
// oneof response {
|
||||
// string thing = 1;
|
||||
// Error not_found = 2 [(tag.reason) = "not_found"];
|
||||
// Error forbidden = 3 [(tag.reason) = "forbidden"];
|
||||
// }
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// Metrics middleware may then inspect `LookupThingResponse` and tag responses
|
||||
// with the provided reason. This is useful when multiple outcomes are
|
||||
// potentially represented with a status = "OK" RPC response.
|
||||
//
|
||||
// Valid messages should only have a single reason set. If a message has
|
||||
// multiple fields present that have a reason option set, no guarantees are
|
||||
// made about the reason that is selected.
|
||||
optional string reason = 71000;
|
||||
}
|
||||
4186
pkg/signalmeow/protobuf/rpc/account/account.pb.go
generated
Normal file
4186
pkg/signalmeow/protobuf/rpc/account/account.pb.go
generated
Normal file
File diff suppressed because it is too large
Load diff
1231
pkg/signalmeow/protobuf/rpc/account/account_grpc.pb.go
generated
Normal file
1231
pkg/signalmeow/protobuf/rpc/account/account_grpc.pb.go
generated
Normal file
File diff suppressed because it is too large
Load diff
357
pkg/signalmeow/protobuf/rpc/attachments/attachments.pb.go
generated
Normal file
357
pkg/signalmeow/protobuf/rpc/attachments/attachments.pb.go
generated
Normal file
|
|
@ -0,0 +1,357 @@
|
|||
//
|
||||
// Copyright 2026 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.11
|
||||
// protoc v7.34.1
|
||||
// source: org/signal/chat/attachments.proto
|
||||
|
||||
package attachments
|
||||
|
||||
import (
|
||||
common "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf/rpc/common"
|
||||
errors "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf/rpc/errors"
|
||||
_ "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf/rpc/require"
|
||||
_ "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf/rpc/tag"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
unsafe "unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type GetUploadFormRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
// The length of the attachment for the requested upload form. Uploads
|
||||
// performed with this form will be limited to the provided length.
|
||||
UploadLength uint64 `protobuf:"varint,1,opt,name=uploadLength,proto3" json:"uploadLength,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *GetUploadFormRequest) Reset() {
|
||||
*x = GetUploadFormRequest{}
|
||||
mi := &file_org_signal_chat_attachments_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *GetUploadFormRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*GetUploadFormRequest) ProtoMessage() {}
|
||||
|
||||
func (x *GetUploadFormRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_org_signal_chat_attachments_proto_msgTypes[0]
|
||||
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 GetUploadFormRequest.ProtoReflect.Descriptor instead.
|
||||
func (*GetUploadFormRequest) Descriptor() ([]byte, []int) {
|
||||
return file_org_signal_chat_attachments_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *GetUploadFormRequest) GetUploadLength() uint64 {
|
||||
if x != nil {
|
||||
return x.UploadLength
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type GetUploadFormResponse struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
// Types that are valid to be assigned to Outcome:
|
||||
//
|
||||
// *GetUploadFormResponse_UploadForm
|
||||
// *GetUploadFormResponse_ExceedsMaxUploadLength
|
||||
Outcome isGetUploadFormResponse_Outcome `protobuf_oneof:"outcome"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *GetUploadFormResponse) Reset() {
|
||||
*x = GetUploadFormResponse{}
|
||||
mi := &file_org_signal_chat_attachments_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *GetUploadFormResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*GetUploadFormResponse) ProtoMessage() {}
|
||||
|
||||
func (x *GetUploadFormResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_org_signal_chat_attachments_proto_msgTypes[1]
|
||||
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 GetUploadFormResponse.ProtoReflect.Descriptor instead.
|
||||
func (*GetUploadFormResponse) Descriptor() ([]byte, []int) {
|
||||
return file_org_signal_chat_attachments_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *GetUploadFormResponse) GetOutcome() isGetUploadFormResponse_Outcome {
|
||||
if x != nil {
|
||||
return x.Outcome
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *GetUploadFormResponse) GetUploadForm() *common.UploadForm {
|
||||
if x != nil {
|
||||
if x, ok := x.Outcome.(*GetUploadFormResponse_UploadForm); ok {
|
||||
return x.UploadForm
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *GetUploadFormResponse) GetExceedsMaxUploadLength() *errors.FailedPrecondition {
|
||||
if x != nil {
|
||||
if x, ok := x.Outcome.(*GetUploadFormResponse_ExceedsMaxUploadLength); ok {
|
||||
return x.ExceedsMaxUploadLength
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type isGetUploadFormResponse_Outcome interface {
|
||||
isGetUploadFormResponse_Outcome()
|
||||
}
|
||||
|
||||
type GetUploadFormResponse_UploadForm struct {
|
||||
UploadForm *common.UploadForm `protobuf:"bytes,1,opt,name=upload_form,json=uploadForm,proto3,oneof"`
|
||||
}
|
||||
|
||||
type GetUploadFormResponse_ExceedsMaxUploadLength struct {
|
||||
// The request size was larger than the maximum supported upload size. The
|
||||
// maximum upload size is subject to change and is governed by
|
||||
// `global.attachments.maxBytes`
|
||||
ExceedsMaxUploadLength *errors.FailedPrecondition `protobuf:"bytes,2,opt,name=exceeds_max_upload_length,json=exceedsMaxUploadLength,proto3,oneof"`
|
||||
}
|
||||
|
||||
func (*GetUploadFormResponse_UploadForm) isGetUploadFormResponse_Outcome() {}
|
||||
|
||||
func (*GetUploadFormResponse_ExceedsMaxUploadLength) isGetUploadFormResponse_Outcome() {}
|
||||
|
||||
type GetStickerUploadFormRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
// The number of stickers in the sticker pack to upload
|
||||
StickerCount uint32 `protobuf:"varint,1,opt,name=sticker_count,json=stickerCount,proto3" json:"sticker_count,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *GetStickerUploadFormRequest) Reset() {
|
||||
*x = GetStickerUploadFormRequest{}
|
||||
mi := &file_org_signal_chat_attachments_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *GetStickerUploadFormRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*GetStickerUploadFormRequest) ProtoMessage() {}
|
||||
|
||||
func (x *GetStickerUploadFormRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_org_signal_chat_attachments_proto_msgTypes[2]
|
||||
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 GetStickerUploadFormRequest.ProtoReflect.Descriptor instead.
|
||||
func (*GetStickerUploadFormRequest) Descriptor() ([]byte, []int) {
|
||||
return file_org_signal_chat_attachments_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
func (x *GetStickerUploadFormRequest) GetStickerCount() uint32 {
|
||||
if x != nil {
|
||||
return x.StickerCount
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type GetStickerUploadFormResponse struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
// A randomly-generated ID for the new sticker pack
|
||||
PackId string `protobuf:"bytes,1,opt,name=pack_id,json=packId,proto3" json:"pack_id,omitempty"`
|
||||
// An upload form clients must use to upload a manifest for the sticker pack
|
||||
ManifestUploadForm *common.S3UploadForm `protobuf:"bytes,2,opt,name=manifest_upload_form,json=manifestUploadForm,proto3" json:"manifest_upload_form,omitempty"`
|
||||
// Upload forms for individual stickers within the sticker pack
|
||||
StickerUploadForms []*common.S3UploadForm `protobuf:"bytes,3,rep,name=sticker_upload_forms,json=stickerUploadForms,proto3" json:"sticker_upload_forms,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *GetStickerUploadFormResponse) Reset() {
|
||||
*x = GetStickerUploadFormResponse{}
|
||||
mi := &file_org_signal_chat_attachments_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *GetStickerUploadFormResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*GetStickerUploadFormResponse) ProtoMessage() {}
|
||||
|
||||
func (x *GetStickerUploadFormResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_org_signal_chat_attachments_proto_msgTypes[3]
|
||||
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 GetStickerUploadFormResponse.ProtoReflect.Descriptor instead.
|
||||
func (*GetStickerUploadFormResponse) Descriptor() ([]byte, []int) {
|
||||
return file_org_signal_chat_attachments_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
func (x *GetStickerUploadFormResponse) GetPackId() string {
|
||||
if x != nil {
|
||||
return x.PackId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *GetStickerUploadFormResponse) GetManifestUploadForm() *common.S3UploadForm {
|
||||
if x != nil {
|
||||
return x.ManifestUploadForm
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *GetStickerUploadFormResponse) GetStickerUploadForms() []*common.S3UploadForm {
|
||||
if x != nil {
|
||||
return x.StickerUploadForms
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_org_signal_chat_attachments_proto protoreflect.FileDescriptor
|
||||
|
||||
const file_org_signal_chat_attachments_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"!org/signal/chat/attachments.proto\x12\x1borg.signal.chat.attachments\x1a\x1corg/signal/chat/common.proto\x1a\x1dorg/signal/chat/require.proto\x1a\x1corg/signal/chat/errors.proto\x1a\x19org/signal/chat/tag.proto\"B\n" +
|
||||
"\x14GetUploadFormRequest\x12*\n" +
|
||||
"\fuploadLength\x18\x01 \x01(\x04B\x06\xb2\x97\"\x02\b\x01R\fuploadLength\"\xe7\x01\n" +
|
||||
"\x15GetUploadFormResponse\x12E\n" +
|
||||
"\vupload_form\x18\x01 \x01(\v2\".org.signal.chat.common.UploadFormH\x00R\n" +
|
||||
"uploadForm\x12|\n" +
|
||||
"\x19exceeds_max_upload_length\x18\x02 \x01(\v2*.org.signal.chat.errors.FailedPreconditionB\x13\xc2\xd5\"\x0foversize_uploadH\x00R\x16exceedsMaxUploadLengthB\t\n" +
|
||||
"\aoutcome\"M\n" +
|
||||
"\x1bGetStickerUploadFormRequest\x12.\n" +
|
||||
"\rsticker_count\x18\x01 \x01(\rB\t\xb2\x97\"\x05\b\x01\x10\xc9\x01R\fstickerCount\"\xe7\x01\n" +
|
||||
"\x1cGetStickerUploadFormResponse\x12\x17\n" +
|
||||
"\apack_id\x18\x01 \x01(\tR\x06packId\x12V\n" +
|
||||
"\x14manifest_upload_form\x18\x02 \x01(\v2$.org.signal.chat.common.S3UploadFormR\x12manifestUploadForm\x12V\n" +
|
||||
"\x14sticker_upload_forms\x18\x03 \x03(\v2$.org.signal.chat.common.S3UploadFormR\x12stickerUploadForms2\x9d\x02\n" +
|
||||
"\vAttachments\x12x\n" +
|
||||
"\rGetUploadForm\x121.org.signal.chat.attachments.GetUploadFormRequest\x1a2.org.signal.chat.attachments.GetUploadFormResponse\"\x00\x12\x8d\x01\n" +
|
||||
"\x14GetStickerUploadForm\x128.org.signal.chat.attachments.GetStickerUploadFormRequest\x1a9.org.signal.chat.attachments.GetStickerUploadFormResponse\"\x00\x1a\x04\xc8\xd5\"\x01B\x02P\x01b\x06proto3"
|
||||
|
||||
var (
|
||||
file_org_signal_chat_attachments_proto_rawDescOnce sync.Once
|
||||
file_org_signal_chat_attachments_proto_rawDescData []byte
|
||||
)
|
||||
|
||||
func file_org_signal_chat_attachments_proto_rawDescGZIP() []byte {
|
||||
file_org_signal_chat_attachments_proto_rawDescOnce.Do(func() {
|
||||
file_org_signal_chat_attachments_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_org_signal_chat_attachments_proto_rawDesc), len(file_org_signal_chat_attachments_proto_rawDesc)))
|
||||
})
|
||||
return file_org_signal_chat_attachments_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_org_signal_chat_attachments_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
|
||||
var file_org_signal_chat_attachments_proto_goTypes = []any{
|
||||
(*GetUploadFormRequest)(nil), // 0: org.signal.chat.attachments.GetUploadFormRequest
|
||||
(*GetUploadFormResponse)(nil), // 1: org.signal.chat.attachments.GetUploadFormResponse
|
||||
(*GetStickerUploadFormRequest)(nil), // 2: org.signal.chat.attachments.GetStickerUploadFormRequest
|
||||
(*GetStickerUploadFormResponse)(nil), // 3: org.signal.chat.attachments.GetStickerUploadFormResponse
|
||||
(*common.UploadForm)(nil), // 4: org.signal.chat.common.UploadForm
|
||||
(*errors.FailedPrecondition)(nil), // 5: org.signal.chat.errors.FailedPrecondition
|
||||
(*common.S3UploadForm)(nil), // 6: org.signal.chat.common.S3UploadForm
|
||||
}
|
||||
var file_org_signal_chat_attachments_proto_depIdxs = []int32{
|
||||
4, // 0: org.signal.chat.attachments.GetUploadFormResponse.upload_form:type_name -> org.signal.chat.common.UploadForm
|
||||
5, // 1: org.signal.chat.attachments.GetUploadFormResponse.exceeds_max_upload_length:type_name -> org.signal.chat.errors.FailedPrecondition
|
||||
6, // 2: org.signal.chat.attachments.GetStickerUploadFormResponse.manifest_upload_form:type_name -> org.signal.chat.common.S3UploadForm
|
||||
6, // 3: org.signal.chat.attachments.GetStickerUploadFormResponse.sticker_upload_forms:type_name -> org.signal.chat.common.S3UploadForm
|
||||
0, // 4: org.signal.chat.attachments.Attachments.GetUploadForm:input_type -> org.signal.chat.attachments.GetUploadFormRequest
|
||||
2, // 5: org.signal.chat.attachments.Attachments.GetStickerUploadForm:input_type -> org.signal.chat.attachments.GetStickerUploadFormRequest
|
||||
1, // 6: org.signal.chat.attachments.Attachments.GetUploadForm:output_type -> org.signal.chat.attachments.GetUploadFormResponse
|
||||
3, // 7: org.signal.chat.attachments.Attachments.GetStickerUploadForm:output_type -> org.signal.chat.attachments.GetStickerUploadFormResponse
|
||||
6, // [6:8] is the sub-list for method output_type
|
||||
4, // [4:6] is the sub-list for method input_type
|
||||
4, // [4:4] is the sub-list for extension type_name
|
||||
4, // [4:4] is the sub-list for extension extendee
|
||||
0, // [0:4] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_org_signal_chat_attachments_proto_init() }
|
||||
func file_org_signal_chat_attachments_proto_init() {
|
||||
if File_org_signal_chat_attachments_proto != nil {
|
||||
return
|
||||
}
|
||||
file_org_signal_chat_attachments_proto_msgTypes[1].OneofWrappers = []any{
|
||||
(*GetUploadFormResponse_UploadForm)(nil),
|
||||
(*GetUploadFormResponse_ExceedsMaxUploadLength)(nil),
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_org_signal_chat_attachments_proto_rawDesc), len(file_org_signal_chat_attachments_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 4,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
GoTypes: file_org_signal_chat_attachments_proto_goTypes,
|
||||
DependencyIndexes: file_org_signal_chat_attachments_proto_depIdxs,
|
||||
MessageInfos: file_org_signal_chat_attachments_proto_msgTypes,
|
||||
}.Build()
|
||||
File_org_signal_chat_attachments_proto = out.File
|
||||
file_org_signal_chat_attachments_proto_goTypes = nil
|
||||
file_org_signal_chat_attachments_proto_depIdxs = nil
|
||||
}
|
||||
167
pkg/signalmeow/protobuf/rpc/attachments/attachments_grpc.pb.go
generated
Normal file
167
pkg/signalmeow/protobuf/rpc/attachments/attachments_grpc.pb.go
generated
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
//
|
||||
// Copyright 2026 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.6.2
|
||||
// - protoc v7.34.1
|
||||
// source: org/signal/chat/attachments.proto
|
||||
|
||||
package attachments
|
||||
|
||||
import (
|
||||
context "context"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
// Requires gRPC-Go v1.64.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion9
|
||||
|
||||
const (
|
||||
Attachments_GetUploadForm_FullMethodName = "/org.signal.chat.attachments.Attachments/GetUploadForm"
|
||||
Attachments_GetStickerUploadForm_FullMethodName = "/org.signal.chat.attachments.Attachments/GetStickerUploadForm"
|
||||
)
|
||||
|
||||
// AttachmentsClient is the client API for Attachments service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
type AttachmentsClient interface {
|
||||
// Retrieve an upload form that can be used to perform a resumable upload
|
||||
GetUploadForm(ctx context.Context, in *GetUploadFormRequest, opts ...grpc.CallOption) (*GetUploadFormResponse, error)
|
||||
// Retrieve an upload form that can be used to upload a sticker pack
|
||||
GetStickerUploadForm(ctx context.Context, in *GetStickerUploadFormRequest, opts ...grpc.CallOption) (*GetStickerUploadFormResponse, error)
|
||||
}
|
||||
|
||||
type attachmentsClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewAttachmentsClient(cc grpc.ClientConnInterface) AttachmentsClient {
|
||||
return &attachmentsClient{cc}
|
||||
}
|
||||
|
||||
func (c *attachmentsClient) GetUploadForm(ctx context.Context, in *GetUploadFormRequest, opts ...grpc.CallOption) (*GetUploadFormResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(GetUploadFormResponse)
|
||||
err := c.cc.Invoke(ctx, Attachments_GetUploadForm_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *attachmentsClient) GetStickerUploadForm(ctx context.Context, in *GetStickerUploadFormRequest, opts ...grpc.CallOption) (*GetStickerUploadFormResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(GetStickerUploadFormResponse)
|
||||
err := c.cc.Invoke(ctx, Attachments_GetStickerUploadForm_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// AttachmentsServer is the server API for Attachments service.
|
||||
// All implementations must embed UnimplementedAttachmentsServer
|
||||
// for forward compatibility.
|
||||
type AttachmentsServer interface {
|
||||
// Retrieve an upload form that can be used to perform a resumable upload
|
||||
GetUploadForm(context.Context, *GetUploadFormRequest) (*GetUploadFormResponse, error)
|
||||
// Retrieve an upload form that can be used to upload a sticker pack
|
||||
GetStickerUploadForm(context.Context, *GetStickerUploadFormRequest) (*GetStickerUploadFormResponse, error)
|
||||
mustEmbedUnimplementedAttachmentsServer()
|
||||
}
|
||||
|
||||
// UnimplementedAttachmentsServer must be embedded to have
|
||||
// forward compatible implementations.
|
||||
//
|
||||
// NOTE: this should be embedded by value instead of pointer to avoid a nil
|
||||
// pointer dereference when methods are called.
|
||||
type UnimplementedAttachmentsServer struct{}
|
||||
|
||||
func (UnimplementedAttachmentsServer) GetUploadForm(context.Context, *GetUploadFormRequest) (*GetUploadFormResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method GetUploadForm not implemented")
|
||||
}
|
||||
func (UnimplementedAttachmentsServer) GetStickerUploadForm(context.Context, *GetStickerUploadFormRequest) (*GetStickerUploadFormResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method GetStickerUploadForm not implemented")
|
||||
}
|
||||
func (UnimplementedAttachmentsServer) mustEmbedUnimplementedAttachmentsServer() {}
|
||||
func (UnimplementedAttachmentsServer) testEmbeddedByValue() {}
|
||||
|
||||
// UnsafeAttachmentsServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to AttachmentsServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeAttachmentsServer interface {
|
||||
mustEmbedUnimplementedAttachmentsServer()
|
||||
}
|
||||
|
||||
func RegisterAttachmentsServer(s grpc.ServiceRegistrar, srv AttachmentsServer) {
|
||||
// If the following call panics, it indicates UnimplementedAttachmentsServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
|
||||
t.testEmbeddedByValue()
|
||||
}
|
||||
s.RegisterService(&Attachments_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _Attachments_GetUploadForm_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(GetUploadFormRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(AttachmentsServer).GetUploadForm(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: Attachments_GetUploadForm_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(AttachmentsServer).GetUploadForm(ctx, req.(*GetUploadFormRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Attachments_GetStickerUploadForm_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(GetStickerUploadFormRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(AttachmentsServer).GetStickerUploadForm(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: Attachments_GetStickerUploadForm_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(AttachmentsServer).GetStickerUploadForm(ctx, req.(*GetStickerUploadFormRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// Attachments_ServiceDesc is the grpc.ServiceDesc for Attachments service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var Attachments_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "org.signal.chat.attachments.Attachments",
|
||||
HandlerType: (*AttachmentsServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "GetUploadForm",
|
||||
Handler: _Attachments_GetUploadForm_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "GetStickerUploadForm",
|
||||
Handler: _Attachments_GetStickerUploadForm_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "org/signal/chat/attachments.proto",
|
||||
}
|
||||
3268
pkg/signalmeow/protobuf/rpc/backups/backups.pb.go
generated
Normal file
3268
pkg/signalmeow/protobuf/rpc/backups/backups.pb.go
generated
Normal file
File diff suppressed because it is too large
Load diff
878
pkg/signalmeow/protobuf/rpc/backups/backups_grpc.pb.go
generated
Normal file
878
pkg/signalmeow/protobuf/rpc/backups/backups_grpc.pb.go
generated
Normal file
|
|
@ -0,0 +1,878 @@
|
|||
//
|
||||
// Copyright 2024 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.6.2
|
||||
// - protoc v7.34.1
|
||||
// source: org/signal/chat/backups.proto
|
||||
|
||||
package backups
|
||||
|
||||
import (
|
||||
context "context"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
// Requires gRPC-Go v1.64.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion9
|
||||
|
||||
const (
|
||||
Backups_SetBackupId_FullMethodName = "/org.signal.chat.backup.Backups/SetBackupId"
|
||||
Backups_RedeemReceipt_FullMethodName = "/org.signal.chat.backup.Backups/RedeemReceipt"
|
||||
Backups_GetBackupAuthCredentials_FullMethodName = "/org.signal.chat.backup.Backups/GetBackupAuthCredentials"
|
||||
)
|
||||
|
||||
// BackupsClient is the client API for Backups service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
//
|
||||
// Service for backup operations that require account authentication.
|
||||
//
|
||||
// Most actual backup operations operate on the backup-id and cannot be linked
|
||||
// to the caller's account, but setting up anonymous credentials and changing
|
||||
// backup tier requires account authentication.
|
||||
type BackupsClient interface {
|
||||
// Set (blinded) backup-id(s) for the account.
|
||||
//
|
||||
// Each account may have a single active backup-id for each credential type
|
||||
// that can be used to store and retrieve backups. Once the backup-id is set,
|
||||
// BackupAuthCredentials can be generated using GetBackupAuthCredentials.
|
||||
//
|
||||
// The blinded backup-id and the key-pair used to blind it must be derived
|
||||
// from a recoverable secret.
|
||||
//
|
||||
// At least one of the credential types must be set on the request.
|
||||
// Only the primary device can set a blinded backup-id.
|
||||
SetBackupId(ctx context.Context, in *SetBackupIdRequest, opts ...grpc.CallOption) (*SetBackupIdResponse, error)
|
||||
// Redeem a receipt acquired from /v1/subscription/{subscriberId}/receipt_credentials
|
||||
// to mark the account as eligible for the paid backup tier.
|
||||
//
|
||||
// After successful redemption, subsequent requests to
|
||||
// GetBackupAuthCredentials will return credentials with the level on the
|
||||
// provided receipt until the expiration time on the receipt.
|
||||
RedeemReceipt(ctx context.Context, in *RedeemReceiptRequest, opts ...grpc.CallOption) (*RedeemReceiptResponse, error)
|
||||
// After setting a blinded backup-id with PUT /v1/archives/, this fetches
|
||||
// credentials that can be used to perform operations against that backup-id.
|
||||
// Clients may (and should) request up to 7 days of credentials at a time.
|
||||
//
|
||||
// The redemption_start and redemption_end seconds must be UTC day aligned, and
|
||||
// must not span more than 7 days.
|
||||
//
|
||||
// Each credential contains a receipt level which indicates the backup level
|
||||
// the credential is good for. If the account has paid backup access that
|
||||
// expires at some point in the provided redemption window, credentials with
|
||||
// redemption times after the expiration may be on a lower backup level.
|
||||
//
|
||||
// Clients must validate the receipt level on the credential matches a known
|
||||
// receipt level before using it.
|
||||
GetBackupAuthCredentials(ctx context.Context, in *GetBackupAuthCredentialsRequest, opts ...grpc.CallOption) (*GetBackupAuthCredentialsResponse, error)
|
||||
}
|
||||
|
||||
type backupsClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewBackupsClient(cc grpc.ClientConnInterface) BackupsClient {
|
||||
return &backupsClient{cc}
|
||||
}
|
||||
|
||||
func (c *backupsClient) SetBackupId(ctx context.Context, in *SetBackupIdRequest, opts ...grpc.CallOption) (*SetBackupIdResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(SetBackupIdResponse)
|
||||
err := c.cc.Invoke(ctx, Backups_SetBackupId_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *backupsClient) RedeemReceipt(ctx context.Context, in *RedeemReceiptRequest, opts ...grpc.CallOption) (*RedeemReceiptResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(RedeemReceiptResponse)
|
||||
err := c.cc.Invoke(ctx, Backups_RedeemReceipt_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *backupsClient) GetBackupAuthCredentials(ctx context.Context, in *GetBackupAuthCredentialsRequest, opts ...grpc.CallOption) (*GetBackupAuthCredentialsResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(GetBackupAuthCredentialsResponse)
|
||||
err := c.cc.Invoke(ctx, Backups_GetBackupAuthCredentials_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// BackupsServer is the server API for Backups service.
|
||||
// All implementations must embed UnimplementedBackupsServer
|
||||
// for forward compatibility.
|
||||
//
|
||||
// Service for backup operations that require account authentication.
|
||||
//
|
||||
// Most actual backup operations operate on the backup-id and cannot be linked
|
||||
// to the caller's account, but setting up anonymous credentials and changing
|
||||
// backup tier requires account authentication.
|
||||
type BackupsServer interface {
|
||||
// Set (blinded) backup-id(s) for the account.
|
||||
//
|
||||
// Each account may have a single active backup-id for each credential type
|
||||
// that can be used to store and retrieve backups. Once the backup-id is set,
|
||||
// BackupAuthCredentials can be generated using GetBackupAuthCredentials.
|
||||
//
|
||||
// The blinded backup-id and the key-pair used to blind it must be derived
|
||||
// from a recoverable secret.
|
||||
//
|
||||
// At least one of the credential types must be set on the request.
|
||||
// Only the primary device can set a blinded backup-id.
|
||||
SetBackupId(context.Context, *SetBackupIdRequest) (*SetBackupIdResponse, error)
|
||||
// Redeem a receipt acquired from /v1/subscription/{subscriberId}/receipt_credentials
|
||||
// to mark the account as eligible for the paid backup tier.
|
||||
//
|
||||
// After successful redemption, subsequent requests to
|
||||
// GetBackupAuthCredentials will return credentials with the level on the
|
||||
// provided receipt until the expiration time on the receipt.
|
||||
RedeemReceipt(context.Context, *RedeemReceiptRequest) (*RedeemReceiptResponse, error)
|
||||
// After setting a blinded backup-id with PUT /v1/archives/, this fetches
|
||||
// credentials that can be used to perform operations against that backup-id.
|
||||
// Clients may (and should) request up to 7 days of credentials at a time.
|
||||
//
|
||||
// The redemption_start and redemption_end seconds must be UTC day aligned, and
|
||||
// must not span more than 7 days.
|
||||
//
|
||||
// Each credential contains a receipt level which indicates the backup level
|
||||
// the credential is good for. If the account has paid backup access that
|
||||
// expires at some point in the provided redemption window, credentials with
|
||||
// redemption times after the expiration may be on a lower backup level.
|
||||
//
|
||||
// Clients must validate the receipt level on the credential matches a known
|
||||
// receipt level before using it.
|
||||
GetBackupAuthCredentials(context.Context, *GetBackupAuthCredentialsRequest) (*GetBackupAuthCredentialsResponse, error)
|
||||
mustEmbedUnimplementedBackupsServer()
|
||||
}
|
||||
|
||||
// UnimplementedBackupsServer must be embedded to have
|
||||
// forward compatible implementations.
|
||||
//
|
||||
// NOTE: this should be embedded by value instead of pointer to avoid a nil
|
||||
// pointer dereference when methods are called.
|
||||
type UnimplementedBackupsServer struct{}
|
||||
|
||||
func (UnimplementedBackupsServer) SetBackupId(context.Context, *SetBackupIdRequest) (*SetBackupIdResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method SetBackupId not implemented")
|
||||
}
|
||||
func (UnimplementedBackupsServer) RedeemReceipt(context.Context, *RedeemReceiptRequest) (*RedeemReceiptResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method RedeemReceipt not implemented")
|
||||
}
|
||||
func (UnimplementedBackupsServer) GetBackupAuthCredentials(context.Context, *GetBackupAuthCredentialsRequest) (*GetBackupAuthCredentialsResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method GetBackupAuthCredentials not implemented")
|
||||
}
|
||||
func (UnimplementedBackupsServer) mustEmbedUnimplementedBackupsServer() {}
|
||||
func (UnimplementedBackupsServer) testEmbeddedByValue() {}
|
||||
|
||||
// UnsafeBackupsServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to BackupsServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeBackupsServer interface {
|
||||
mustEmbedUnimplementedBackupsServer()
|
||||
}
|
||||
|
||||
func RegisterBackupsServer(s grpc.ServiceRegistrar, srv BackupsServer) {
|
||||
// If the following call panics, it indicates UnimplementedBackupsServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
|
||||
t.testEmbeddedByValue()
|
||||
}
|
||||
s.RegisterService(&Backups_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _Backups_SetBackupId_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(SetBackupIdRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(BackupsServer).SetBackupId(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: Backups_SetBackupId_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(BackupsServer).SetBackupId(ctx, req.(*SetBackupIdRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Backups_RedeemReceipt_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(RedeemReceiptRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(BackupsServer).RedeemReceipt(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: Backups_RedeemReceipt_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(BackupsServer).RedeemReceipt(ctx, req.(*RedeemReceiptRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Backups_GetBackupAuthCredentials_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(GetBackupAuthCredentialsRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(BackupsServer).GetBackupAuthCredentials(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: Backups_GetBackupAuthCredentials_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(BackupsServer).GetBackupAuthCredentials(ctx, req.(*GetBackupAuthCredentialsRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// Backups_ServiceDesc is the grpc.ServiceDesc for Backups service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var Backups_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "org.signal.chat.backup.Backups",
|
||||
HandlerType: (*BackupsServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "SetBackupId",
|
||||
Handler: _Backups_SetBackupId_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "RedeemReceipt",
|
||||
Handler: _Backups_RedeemReceipt_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "GetBackupAuthCredentials",
|
||||
Handler: _Backups_GetBackupAuthCredentials_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "org/signal/chat/backups.proto",
|
||||
}
|
||||
|
||||
const (
|
||||
BackupsAnonymous_GetCdnCredentials_FullMethodName = "/org.signal.chat.backup.BackupsAnonymous/GetCdnCredentials"
|
||||
BackupsAnonymous_GetSvrBCredentials_FullMethodName = "/org.signal.chat.backup.BackupsAnonymous/GetSvrBCredentials"
|
||||
BackupsAnonymous_GetMessageBackupInfo_FullMethodName = "/org.signal.chat.backup.BackupsAnonymous/GetMessageBackupInfo"
|
||||
BackupsAnonymous_GetMediaBackupInfo_FullMethodName = "/org.signal.chat.backup.BackupsAnonymous/GetMediaBackupInfo"
|
||||
BackupsAnonymous_SetPublicKey_FullMethodName = "/org.signal.chat.backup.BackupsAnonymous/SetPublicKey"
|
||||
BackupsAnonymous_Refresh_FullMethodName = "/org.signal.chat.backup.BackupsAnonymous/Refresh"
|
||||
BackupsAnonymous_GetUploadForm_FullMethodName = "/org.signal.chat.backup.BackupsAnonymous/GetUploadForm"
|
||||
BackupsAnonymous_CopyMedia_FullMethodName = "/org.signal.chat.backup.BackupsAnonymous/CopyMedia"
|
||||
BackupsAnonymous_ListMedia_FullMethodName = "/org.signal.chat.backup.BackupsAnonymous/ListMedia"
|
||||
BackupsAnonymous_DeleteMedia_FullMethodName = "/org.signal.chat.backup.BackupsAnonymous/DeleteMedia"
|
||||
BackupsAnonymous_DeleteAll_FullMethodName = "/org.signal.chat.backup.BackupsAnonymous/DeleteAll"
|
||||
)
|
||||
|
||||
// BackupsAnonymousClient is the client API for BackupsAnonymous service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
//
|
||||
// # Service for backup operations with anonymous credentials
|
||||
//
|
||||
// This service never requires account authentication. It instead requires a
|
||||
// backup-id authenticated with an anonymous credential that cannot be linked
|
||||
// to the account.
|
||||
//
|
||||
// To register an anonymous credential:
|
||||
//
|
||||
// 1. Set a backup-id on the authenticated channel via Backups::SetBackupId
|
||||
// 2. Retrieve BackupAuthCredentials via Backups::GetBackupAuthCredentials
|
||||
// 3. Generate a key pair and set the public key via
|
||||
// BackupsAnonymous::SetPublicKey
|
||||
//
|
||||
// Unless otherwise noted, requests for this service require a
|
||||
// SignedPresentation, which includes:
|
||||
//
|
||||
// - a presentation generated from a BackupAuthCredential issued by
|
||||
// GetBackupAuthCredentials
|
||||
// - a signature of that presentation using the private key of a key pair
|
||||
// previously set with SetPublicKey.
|
||||
type BackupsAnonymousClient interface {
|
||||
// Retrieve credentials used to read objects stored on the backup cdn
|
||||
GetCdnCredentials(ctx context.Context, in *GetCdnCredentialsRequest, opts ...grpc.CallOption) (*GetCdnCredentialsResponse, error)
|
||||
// Retrieve credentials used to interact with the SecureValueRecoveryB service
|
||||
GetSvrBCredentials(ctx context.Context, in *GetSvrBCredentialsRequest, opts ...grpc.CallOption) (*GetSvrBCredentialsResponse, error)
|
||||
// Retrieve information about the currently stored message backup
|
||||
GetMessageBackupInfo(ctx context.Context, in *GetBackupInfoRequest, opts ...grpc.CallOption) (*GetMessageBackupInfoResponse, error)
|
||||
// Retrieve information about the currently stored media backup
|
||||
GetMediaBackupInfo(ctx context.Context, in *GetBackupInfoRequest, opts ...grpc.CallOption) (*GetMediaBackupInfoResponse, error)
|
||||
// Permanently set the public key of an ED25519 key-pair for the backup-id.
|
||||
// All requests (including this one!) must sign their BackupAuthCredential
|
||||
// presentations with the private key corresponding to the provided public key.
|
||||
SetPublicKey(ctx context.Context, in *SetPublicKeyRequest, opts ...grpc.CallOption) (*SetPublicKeyResponse, error)
|
||||
// Refresh the backup, indicating that the backup is still active. Clients
|
||||
// must periodically upload new backups or perform a refresh. If a backup has
|
||||
// not been active for 30 days, it may be deleted.
|
||||
Refresh(ctx context.Context, in *RefreshRequest, opts ...grpc.CallOption) (*RefreshResponse, error)
|
||||
// Retrieve an upload form that can be used to perform a resumable upload
|
||||
GetUploadForm(ctx context.Context, in *GetUploadFormRequest, opts ...grpc.CallOption) (*GetUploadFormResponse, error)
|
||||
// Copy and re-encrypt media from the attachments cdn into the backup cdn.
|
||||
// The original, already encrypted, attachments will be encrypted with the
|
||||
// provided key material before being copied.
|
||||
//
|
||||
// The copy operation is not atomic and responses will be returned as copy
|
||||
// operations complete with detailed information about the outcome. If an
|
||||
// error is encountered, not all requests may be reflected in the responses.
|
||||
//
|
||||
// On retries, a particular destination media id must not be reused with a
|
||||
// different source media id or different encryption parameters.
|
||||
//
|
||||
// The response stream may be closed with STREAM_CLOSED error reason. In this
|
||||
// case, a BackupStreamClosed message will be present in the error details.
|
||||
CopyMedia(ctx context.Context, in *CopyMediaRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[CopyMediaResponse], error)
|
||||
// Retrieve a page of media objects stored for this backup-id. A client may
|
||||
// have previously stored media objects that are no longer referenced in their
|
||||
// current backup. To reclaim storage space used by these orphaned objects,
|
||||
// perform a list operation and remove any unreferenced media objects
|
||||
// via DeleteMedia.
|
||||
ListMedia(ctx context.Context, in *ListMediaRequest, opts ...grpc.CallOption) (*ListMediaResponse, error)
|
||||
// Delete media objects stored with this backup-id. Streams the locations of
|
||||
// media items back when the item has successfully been removed.
|
||||
//
|
||||
// The response stream may be closed with STREAM_CLOSED error reason. In this
|
||||
// case, a BackupStreamClosed message will be present in the error details.
|
||||
DeleteMedia(ctx context.Context, in *DeleteMediaRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[DeleteMediaResponse], error)
|
||||
// Delete all backup metadata, objects, and stored public key. To use
|
||||
// backups again, a public key must be resupplied.
|
||||
DeleteAll(ctx context.Context, in *DeleteAllRequest, opts ...grpc.CallOption) (*DeleteAllResponse, error)
|
||||
}
|
||||
|
||||
type backupsAnonymousClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewBackupsAnonymousClient(cc grpc.ClientConnInterface) BackupsAnonymousClient {
|
||||
return &backupsAnonymousClient{cc}
|
||||
}
|
||||
|
||||
func (c *backupsAnonymousClient) GetCdnCredentials(ctx context.Context, in *GetCdnCredentialsRequest, opts ...grpc.CallOption) (*GetCdnCredentialsResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(GetCdnCredentialsResponse)
|
||||
err := c.cc.Invoke(ctx, BackupsAnonymous_GetCdnCredentials_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *backupsAnonymousClient) GetSvrBCredentials(ctx context.Context, in *GetSvrBCredentialsRequest, opts ...grpc.CallOption) (*GetSvrBCredentialsResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(GetSvrBCredentialsResponse)
|
||||
err := c.cc.Invoke(ctx, BackupsAnonymous_GetSvrBCredentials_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *backupsAnonymousClient) GetMessageBackupInfo(ctx context.Context, in *GetBackupInfoRequest, opts ...grpc.CallOption) (*GetMessageBackupInfoResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(GetMessageBackupInfoResponse)
|
||||
err := c.cc.Invoke(ctx, BackupsAnonymous_GetMessageBackupInfo_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *backupsAnonymousClient) GetMediaBackupInfo(ctx context.Context, in *GetBackupInfoRequest, opts ...grpc.CallOption) (*GetMediaBackupInfoResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(GetMediaBackupInfoResponse)
|
||||
err := c.cc.Invoke(ctx, BackupsAnonymous_GetMediaBackupInfo_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *backupsAnonymousClient) SetPublicKey(ctx context.Context, in *SetPublicKeyRequest, opts ...grpc.CallOption) (*SetPublicKeyResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(SetPublicKeyResponse)
|
||||
err := c.cc.Invoke(ctx, BackupsAnonymous_SetPublicKey_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *backupsAnonymousClient) Refresh(ctx context.Context, in *RefreshRequest, opts ...grpc.CallOption) (*RefreshResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(RefreshResponse)
|
||||
err := c.cc.Invoke(ctx, BackupsAnonymous_Refresh_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *backupsAnonymousClient) GetUploadForm(ctx context.Context, in *GetUploadFormRequest, opts ...grpc.CallOption) (*GetUploadFormResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(GetUploadFormResponse)
|
||||
err := c.cc.Invoke(ctx, BackupsAnonymous_GetUploadForm_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *backupsAnonymousClient) CopyMedia(ctx context.Context, in *CopyMediaRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[CopyMediaResponse], error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
stream, err := c.cc.NewStream(ctx, &BackupsAnonymous_ServiceDesc.Streams[0], BackupsAnonymous_CopyMedia_FullMethodName, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
x := &grpc.GenericClientStream[CopyMediaRequest, CopyMediaResponse]{ClientStream: stream}
|
||||
if err := x.ClientStream.SendMsg(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := x.ClientStream.CloseSend(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return x, nil
|
||||
}
|
||||
|
||||
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
|
||||
type BackupsAnonymous_CopyMediaClient = grpc.ServerStreamingClient[CopyMediaResponse]
|
||||
|
||||
func (c *backupsAnonymousClient) ListMedia(ctx context.Context, in *ListMediaRequest, opts ...grpc.CallOption) (*ListMediaResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(ListMediaResponse)
|
||||
err := c.cc.Invoke(ctx, BackupsAnonymous_ListMedia_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *backupsAnonymousClient) DeleteMedia(ctx context.Context, in *DeleteMediaRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[DeleteMediaResponse], error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
stream, err := c.cc.NewStream(ctx, &BackupsAnonymous_ServiceDesc.Streams[1], BackupsAnonymous_DeleteMedia_FullMethodName, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
x := &grpc.GenericClientStream[DeleteMediaRequest, DeleteMediaResponse]{ClientStream: stream}
|
||||
if err := x.ClientStream.SendMsg(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := x.ClientStream.CloseSend(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return x, nil
|
||||
}
|
||||
|
||||
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
|
||||
type BackupsAnonymous_DeleteMediaClient = grpc.ServerStreamingClient[DeleteMediaResponse]
|
||||
|
||||
func (c *backupsAnonymousClient) DeleteAll(ctx context.Context, in *DeleteAllRequest, opts ...grpc.CallOption) (*DeleteAllResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(DeleteAllResponse)
|
||||
err := c.cc.Invoke(ctx, BackupsAnonymous_DeleteAll_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// BackupsAnonymousServer is the server API for BackupsAnonymous service.
|
||||
// All implementations must embed UnimplementedBackupsAnonymousServer
|
||||
// for forward compatibility.
|
||||
//
|
||||
// # Service for backup operations with anonymous credentials
|
||||
//
|
||||
// This service never requires account authentication. It instead requires a
|
||||
// backup-id authenticated with an anonymous credential that cannot be linked
|
||||
// to the account.
|
||||
//
|
||||
// To register an anonymous credential:
|
||||
//
|
||||
// 1. Set a backup-id on the authenticated channel via Backups::SetBackupId
|
||||
// 2. Retrieve BackupAuthCredentials via Backups::GetBackupAuthCredentials
|
||||
// 3. Generate a key pair and set the public key via
|
||||
// BackupsAnonymous::SetPublicKey
|
||||
//
|
||||
// Unless otherwise noted, requests for this service require a
|
||||
// SignedPresentation, which includes:
|
||||
//
|
||||
// - a presentation generated from a BackupAuthCredential issued by
|
||||
// GetBackupAuthCredentials
|
||||
// - a signature of that presentation using the private key of a key pair
|
||||
// previously set with SetPublicKey.
|
||||
type BackupsAnonymousServer interface {
|
||||
// Retrieve credentials used to read objects stored on the backup cdn
|
||||
GetCdnCredentials(context.Context, *GetCdnCredentialsRequest) (*GetCdnCredentialsResponse, error)
|
||||
// Retrieve credentials used to interact with the SecureValueRecoveryB service
|
||||
GetSvrBCredentials(context.Context, *GetSvrBCredentialsRequest) (*GetSvrBCredentialsResponse, error)
|
||||
// Retrieve information about the currently stored message backup
|
||||
GetMessageBackupInfo(context.Context, *GetBackupInfoRequest) (*GetMessageBackupInfoResponse, error)
|
||||
// Retrieve information about the currently stored media backup
|
||||
GetMediaBackupInfo(context.Context, *GetBackupInfoRequest) (*GetMediaBackupInfoResponse, error)
|
||||
// Permanently set the public key of an ED25519 key-pair for the backup-id.
|
||||
// All requests (including this one!) must sign their BackupAuthCredential
|
||||
// presentations with the private key corresponding to the provided public key.
|
||||
SetPublicKey(context.Context, *SetPublicKeyRequest) (*SetPublicKeyResponse, error)
|
||||
// Refresh the backup, indicating that the backup is still active. Clients
|
||||
// must periodically upload new backups or perform a refresh. If a backup has
|
||||
// not been active for 30 days, it may be deleted.
|
||||
Refresh(context.Context, *RefreshRequest) (*RefreshResponse, error)
|
||||
// Retrieve an upload form that can be used to perform a resumable upload
|
||||
GetUploadForm(context.Context, *GetUploadFormRequest) (*GetUploadFormResponse, error)
|
||||
// Copy and re-encrypt media from the attachments cdn into the backup cdn.
|
||||
// The original, already encrypted, attachments will be encrypted with the
|
||||
// provided key material before being copied.
|
||||
//
|
||||
// The copy operation is not atomic and responses will be returned as copy
|
||||
// operations complete with detailed information about the outcome. If an
|
||||
// error is encountered, not all requests may be reflected in the responses.
|
||||
//
|
||||
// On retries, a particular destination media id must not be reused with a
|
||||
// different source media id or different encryption parameters.
|
||||
//
|
||||
// The response stream may be closed with STREAM_CLOSED error reason. In this
|
||||
// case, a BackupStreamClosed message will be present in the error details.
|
||||
CopyMedia(*CopyMediaRequest, grpc.ServerStreamingServer[CopyMediaResponse]) error
|
||||
// Retrieve a page of media objects stored for this backup-id. A client may
|
||||
// have previously stored media objects that are no longer referenced in their
|
||||
// current backup. To reclaim storage space used by these orphaned objects,
|
||||
// perform a list operation and remove any unreferenced media objects
|
||||
// via DeleteMedia.
|
||||
ListMedia(context.Context, *ListMediaRequest) (*ListMediaResponse, error)
|
||||
// Delete media objects stored with this backup-id. Streams the locations of
|
||||
// media items back when the item has successfully been removed.
|
||||
//
|
||||
// The response stream may be closed with STREAM_CLOSED error reason. In this
|
||||
// case, a BackupStreamClosed message will be present in the error details.
|
||||
DeleteMedia(*DeleteMediaRequest, grpc.ServerStreamingServer[DeleteMediaResponse]) error
|
||||
// Delete all backup metadata, objects, and stored public key. To use
|
||||
// backups again, a public key must be resupplied.
|
||||
DeleteAll(context.Context, *DeleteAllRequest) (*DeleteAllResponse, error)
|
||||
mustEmbedUnimplementedBackupsAnonymousServer()
|
||||
}
|
||||
|
||||
// UnimplementedBackupsAnonymousServer must be embedded to have
|
||||
// forward compatible implementations.
|
||||
//
|
||||
// NOTE: this should be embedded by value instead of pointer to avoid a nil
|
||||
// pointer dereference when methods are called.
|
||||
type UnimplementedBackupsAnonymousServer struct{}
|
||||
|
||||
func (UnimplementedBackupsAnonymousServer) GetCdnCredentials(context.Context, *GetCdnCredentialsRequest) (*GetCdnCredentialsResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method GetCdnCredentials not implemented")
|
||||
}
|
||||
func (UnimplementedBackupsAnonymousServer) GetSvrBCredentials(context.Context, *GetSvrBCredentialsRequest) (*GetSvrBCredentialsResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method GetSvrBCredentials not implemented")
|
||||
}
|
||||
func (UnimplementedBackupsAnonymousServer) GetMessageBackupInfo(context.Context, *GetBackupInfoRequest) (*GetMessageBackupInfoResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method GetMessageBackupInfo not implemented")
|
||||
}
|
||||
func (UnimplementedBackupsAnonymousServer) GetMediaBackupInfo(context.Context, *GetBackupInfoRequest) (*GetMediaBackupInfoResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method GetMediaBackupInfo not implemented")
|
||||
}
|
||||
func (UnimplementedBackupsAnonymousServer) SetPublicKey(context.Context, *SetPublicKeyRequest) (*SetPublicKeyResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method SetPublicKey not implemented")
|
||||
}
|
||||
func (UnimplementedBackupsAnonymousServer) Refresh(context.Context, *RefreshRequest) (*RefreshResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method Refresh not implemented")
|
||||
}
|
||||
func (UnimplementedBackupsAnonymousServer) GetUploadForm(context.Context, *GetUploadFormRequest) (*GetUploadFormResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method GetUploadForm not implemented")
|
||||
}
|
||||
func (UnimplementedBackupsAnonymousServer) CopyMedia(*CopyMediaRequest, grpc.ServerStreamingServer[CopyMediaResponse]) error {
|
||||
return status.Error(codes.Unimplemented, "method CopyMedia not implemented")
|
||||
}
|
||||
func (UnimplementedBackupsAnonymousServer) ListMedia(context.Context, *ListMediaRequest) (*ListMediaResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method ListMedia not implemented")
|
||||
}
|
||||
func (UnimplementedBackupsAnonymousServer) DeleteMedia(*DeleteMediaRequest, grpc.ServerStreamingServer[DeleteMediaResponse]) error {
|
||||
return status.Error(codes.Unimplemented, "method DeleteMedia not implemented")
|
||||
}
|
||||
func (UnimplementedBackupsAnonymousServer) DeleteAll(context.Context, *DeleteAllRequest) (*DeleteAllResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method DeleteAll not implemented")
|
||||
}
|
||||
func (UnimplementedBackupsAnonymousServer) mustEmbedUnimplementedBackupsAnonymousServer() {}
|
||||
func (UnimplementedBackupsAnonymousServer) testEmbeddedByValue() {}
|
||||
|
||||
// UnsafeBackupsAnonymousServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to BackupsAnonymousServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeBackupsAnonymousServer interface {
|
||||
mustEmbedUnimplementedBackupsAnonymousServer()
|
||||
}
|
||||
|
||||
func RegisterBackupsAnonymousServer(s grpc.ServiceRegistrar, srv BackupsAnonymousServer) {
|
||||
// If the following call panics, it indicates UnimplementedBackupsAnonymousServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
|
||||
t.testEmbeddedByValue()
|
||||
}
|
||||
s.RegisterService(&BackupsAnonymous_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _BackupsAnonymous_GetCdnCredentials_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(GetCdnCredentialsRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(BackupsAnonymousServer).GetCdnCredentials(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: BackupsAnonymous_GetCdnCredentials_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(BackupsAnonymousServer).GetCdnCredentials(ctx, req.(*GetCdnCredentialsRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _BackupsAnonymous_GetSvrBCredentials_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(GetSvrBCredentialsRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(BackupsAnonymousServer).GetSvrBCredentials(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: BackupsAnonymous_GetSvrBCredentials_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(BackupsAnonymousServer).GetSvrBCredentials(ctx, req.(*GetSvrBCredentialsRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _BackupsAnonymous_GetMessageBackupInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(GetBackupInfoRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(BackupsAnonymousServer).GetMessageBackupInfo(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: BackupsAnonymous_GetMessageBackupInfo_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(BackupsAnonymousServer).GetMessageBackupInfo(ctx, req.(*GetBackupInfoRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _BackupsAnonymous_GetMediaBackupInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(GetBackupInfoRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(BackupsAnonymousServer).GetMediaBackupInfo(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: BackupsAnonymous_GetMediaBackupInfo_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(BackupsAnonymousServer).GetMediaBackupInfo(ctx, req.(*GetBackupInfoRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _BackupsAnonymous_SetPublicKey_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(SetPublicKeyRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(BackupsAnonymousServer).SetPublicKey(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: BackupsAnonymous_SetPublicKey_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(BackupsAnonymousServer).SetPublicKey(ctx, req.(*SetPublicKeyRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _BackupsAnonymous_Refresh_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(RefreshRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(BackupsAnonymousServer).Refresh(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: BackupsAnonymous_Refresh_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(BackupsAnonymousServer).Refresh(ctx, req.(*RefreshRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _BackupsAnonymous_GetUploadForm_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(GetUploadFormRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(BackupsAnonymousServer).GetUploadForm(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: BackupsAnonymous_GetUploadForm_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(BackupsAnonymousServer).GetUploadForm(ctx, req.(*GetUploadFormRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _BackupsAnonymous_CopyMedia_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||
m := new(CopyMediaRequest)
|
||||
if err := stream.RecvMsg(m); err != nil {
|
||||
return err
|
||||
}
|
||||
return srv.(BackupsAnonymousServer).CopyMedia(m, &grpc.GenericServerStream[CopyMediaRequest, CopyMediaResponse]{ServerStream: stream})
|
||||
}
|
||||
|
||||
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
|
||||
type BackupsAnonymous_CopyMediaServer = grpc.ServerStreamingServer[CopyMediaResponse]
|
||||
|
||||
func _BackupsAnonymous_ListMedia_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ListMediaRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(BackupsAnonymousServer).ListMedia(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: BackupsAnonymous_ListMedia_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(BackupsAnonymousServer).ListMedia(ctx, req.(*ListMediaRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _BackupsAnonymous_DeleteMedia_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||
m := new(DeleteMediaRequest)
|
||||
if err := stream.RecvMsg(m); err != nil {
|
||||
return err
|
||||
}
|
||||
return srv.(BackupsAnonymousServer).DeleteMedia(m, &grpc.GenericServerStream[DeleteMediaRequest, DeleteMediaResponse]{ServerStream: stream})
|
||||
}
|
||||
|
||||
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
|
||||
type BackupsAnonymous_DeleteMediaServer = grpc.ServerStreamingServer[DeleteMediaResponse]
|
||||
|
||||
func _BackupsAnonymous_DeleteAll_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(DeleteAllRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(BackupsAnonymousServer).DeleteAll(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: BackupsAnonymous_DeleteAll_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(BackupsAnonymousServer).DeleteAll(ctx, req.(*DeleteAllRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// BackupsAnonymous_ServiceDesc is the grpc.ServiceDesc for BackupsAnonymous service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var BackupsAnonymous_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "org.signal.chat.backup.BackupsAnonymous",
|
||||
HandlerType: (*BackupsAnonymousServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "GetCdnCredentials",
|
||||
Handler: _BackupsAnonymous_GetCdnCredentials_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "GetSvrBCredentials",
|
||||
Handler: _BackupsAnonymous_GetSvrBCredentials_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "GetMessageBackupInfo",
|
||||
Handler: _BackupsAnonymous_GetMessageBackupInfo_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "GetMediaBackupInfo",
|
||||
Handler: _BackupsAnonymous_GetMediaBackupInfo_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "SetPublicKey",
|
||||
Handler: _BackupsAnonymous_SetPublicKey_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "Refresh",
|
||||
Handler: _BackupsAnonymous_Refresh_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "GetUploadForm",
|
||||
Handler: _BackupsAnonymous_GetUploadForm_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "ListMedia",
|
||||
Handler: _BackupsAnonymous_ListMedia_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "DeleteAll",
|
||||
Handler: _BackupsAnonymous_DeleteAll_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{
|
||||
{
|
||||
StreamName: "CopyMedia",
|
||||
Handler: _BackupsAnonymous_CopyMedia_Handler,
|
||||
ServerStreams: true,
|
||||
},
|
||||
{
|
||||
StreamName: "DeleteMedia",
|
||||
Handler: _BackupsAnonymous_DeleteMedia_Handler,
|
||||
ServerStreams: true,
|
||||
},
|
||||
},
|
||||
Metadata: "org/signal/chat/backups.proto",
|
||||
}
|
||||
426
pkg/signalmeow/protobuf/rpc/call_quality/call_quality.pb.go
generated
Normal file
426
pkg/signalmeow/protobuf/rpc/call_quality/call_quality.pb.go
generated
Normal file
|
|
@ -0,0 +1,426 @@
|
|||
//
|
||||
// Copyright 2025 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.11
|
||||
// protoc v7.34.1
|
||||
// source: org/signal/chat/call_quality.proto
|
||||
|
||||
package call_quality
|
||||
|
||||
import (
|
||||
_ "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf/rpc/require"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
unsafe "unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type SubmitCallQualitySurveyRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
// Indicates whether the caller was generally satisfied with the quality of
|
||||
// the call
|
||||
UserSatisfied bool `protobuf:"varint,1,opt,name=user_satisfied,json=userSatisfied,proto3" json:"user_satisfied,omitempty"`
|
||||
// A list of call quality issues selected by the caller
|
||||
CallQualityIssues []string `protobuf:"bytes,2,rep,name=call_quality_issues,json=callQualityIssues,proto3" json:"call_quality_issues,omitempty"`
|
||||
// A free-form description of any additional issues as written by the caller
|
||||
AdditionalIssuesDescription *string `protobuf:"bytes,3,opt,name=additional_issues_description,json=additionalIssuesDescription,proto3,oneof" json:"additional_issues_description,omitempty"`
|
||||
// A URL for a set of debug logs associated with the call if the caller chose
|
||||
// to submit debug logs
|
||||
DebugLogUrl *string `protobuf:"bytes,4,opt,name=debug_log_url,json=debugLogUrl,proto3,oneof" json:"debug_log_url,omitempty"`
|
||||
// The time at which the call started in milliseconds since the epoch
|
||||
StartTimestamp int64 `protobuf:"varint,5,opt,name=start_timestamp,json=startTimestamp,proto3" json:"start_timestamp,omitempty"`
|
||||
// The time at which the call ended in milliseconds since the epoch
|
||||
EndTimestamp int64 `protobuf:"varint,6,opt,name=end_timestamp,json=endTimestamp,proto3" json:"end_timestamp,omitempty"`
|
||||
// The type of call; note that direct voice calls can become video calls and
|
||||
// vice versa, and this field indicates which mode was selected at call
|
||||
// initiation time. At the time of writing, expected call types are
|
||||
// "direct_voice", "direct_video", "group", and "call_link".
|
||||
CallType string `protobuf:"bytes,7,opt,name=call_type,json=callType,proto3" json:"call_type,omitempty"`
|
||||
// Indicates whether the call completed without error or if it terminated
|
||||
// abnormally
|
||||
Success bool `protobuf:"varint,8,opt,name=success,proto3" json:"success,omitempty"`
|
||||
// A client-defined, but human-readable reason for call termination
|
||||
CallEndReason string `protobuf:"bytes,9,opt,name=call_end_reason,json=callEndReason,proto3" json:"call_end_reason,omitempty"`
|
||||
// The median round-trip time, measured in milliseconds, for STUN/ICE packets
|
||||
// (i.e. connection maintenance and establishment)
|
||||
ConnectionRttMedian *float32 `protobuf:"fixed32,10,opt,name=connection_rtt_median,json=connectionRttMedian,proto3,oneof" json:"connection_rtt_median,omitempty"`
|
||||
// The median round-trip time, measured in milliseconds, for RTP/RTCP packets
|
||||
// for audio streams
|
||||
AudioRttMedian *float32 `protobuf:"fixed32,11,opt,name=audio_rtt_median,json=audioRttMedian,proto3,oneof" json:"audio_rtt_median,omitempty"`
|
||||
// The median round-trip time, measured in milliseconds, for RTP/RTCP packets
|
||||
// for video streams
|
||||
VideoRttMedian *float32 `protobuf:"fixed32,12,opt,name=video_rtt_median,json=videoRttMedian,proto3,oneof" json:"video_rtt_median,omitempty"`
|
||||
// The median jitter for audio streams, measured in milliseconds, for the
|
||||
// duration of the call as measured by the client submitting the survey
|
||||
AudioRecvJitterMedian *float32 `protobuf:"fixed32,13,opt,name=audio_recv_jitter_median,json=audioRecvJitterMedian,proto3,oneof" json:"audio_recv_jitter_median,omitempty"`
|
||||
// The median jitter for video streams, measured in milliseconds, for the
|
||||
// duration of the call as measured by the client submitting the survey
|
||||
VideoRecvJitterMedian *float32 `protobuf:"fixed32,14,opt,name=video_recv_jitter_median,json=videoRecvJitterMedian,proto3,oneof" json:"video_recv_jitter_median,omitempty"`
|
||||
// The median jitter for audio streams, measured in milliseconds, for the
|
||||
// duration of the call as measured by the remote endpoint in the call (either
|
||||
// the peer of the client submitting the survey in a direct call or the SFU in
|
||||
// a group call)
|
||||
AudioSendJitterMedian *float32 `protobuf:"fixed32,15,opt,name=audio_send_jitter_median,json=audioSendJitterMedian,proto3,oneof" json:"audio_send_jitter_median,omitempty"`
|
||||
// The median jitter for video streams, measured in milliseconds, for the
|
||||
// duration of the call as measured by the remote endpoint in the call (either
|
||||
// the peer of the client submitting the survey in a direct call or the SFU in
|
||||
// a group call)
|
||||
VideoSendJitterMedian *float32 `protobuf:"fixed32,16,opt,name=video_send_jitter_median,json=videoSendJitterMedian,proto3,oneof" json:"video_send_jitter_median,omitempty"`
|
||||
// The fraction of audio packets lost over the duration of the call as
|
||||
// measured by the client submitting the survey
|
||||
AudioRecvPacketLossFraction *float32 `protobuf:"fixed32,17,opt,name=audio_recv_packet_loss_fraction,json=audioRecvPacketLossFraction,proto3,oneof" json:"audio_recv_packet_loss_fraction,omitempty"`
|
||||
// The fraction of video packets lost over the duration of the call as
|
||||
// measured by the client submitting the survey
|
||||
VideoRecvPacketLossFraction *float32 `protobuf:"fixed32,18,opt,name=video_recv_packet_loss_fraction,json=videoRecvPacketLossFraction,proto3,oneof" json:"video_recv_packet_loss_fraction,omitempty"`
|
||||
// The fraction of audio packets lost over the duration of the call as
|
||||
// measured by the remote endpoint in the call (either the peer of the client
|
||||
// submitting the survey in a direct call or the SFU in a group call)
|
||||
AudioSendPacketLossFraction *float32 `protobuf:"fixed32,19,opt,name=audio_send_packet_loss_fraction,json=audioSendPacketLossFraction,proto3,oneof" json:"audio_send_packet_loss_fraction,omitempty"`
|
||||
// The fraction of video packets lost over the duration of the call as
|
||||
// measured by the remote endpoint in the call (either the peer of the client
|
||||
// submitting the survey in a direct call or the SFU in a group call)
|
||||
VideoSendPacketLossFraction *float32 `protobuf:"fixed32,20,opt,name=video_send_packet_loss_fraction,json=videoSendPacketLossFraction,proto3,oneof" json:"video_send_packet_loss_fraction,omitempty"`
|
||||
// Machine-generated telemetry from the call; this is a serialized protobuf
|
||||
// entity generated (and, critically, explained to the user!) by the calling
|
||||
// library
|
||||
CallTelemetry []byte `protobuf:"bytes,21,opt,name=call_telemetry,json=callTelemetry,proto3,oneof" json:"call_telemetry,omitempty"`
|
||||
// A hash of a call ID (shared between clients and never sent to the calling
|
||||
// server) that can be used to correlate survey responses from multiple
|
||||
// participants in a call
|
||||
CallIdHash []byte `protobuf:"bytes,22,opt,name=call_id_hash,json=callIdHash,proto3,oneof" json:"call_id_hash,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *SubmitCallQualitySurveyRequest) Reset() {
|
||||
*x = SubmitCallQualitySurveyRequest{}
|
||||
mi := &file_org_signal_chat_call_quality_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *SubmitCallQualitySurveyRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*SubmitCallQualitySurveyRequest) ProtoMessage() {}
|
||||
|
||||
func (x *SubmitCallQualitySurveyRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_org_signal_chat_call_quality_proto_msgTypes[0]
|
||||
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 SubmitCallQualitySurveyRequest.ProtoReflect.Descriptor instead.
|
||||
func (*SubmitCallQualitySurveyRequest) Descriptor() ([]byte, []int) {
|
||||
return file_org_signal_chat_call_quality_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *SubmitCallQualitySurveyRequest) GetUserSatisfied() bool {
|
||||
if x != nil {
|
||||
return x.UserSatisfied
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *SubmitCallQualitySurveyRequest) GetCallQualityIssues() []string {
|
||||
if x != nil {
|
||||
return x.CallQualityIssues
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *SubmitCallQualitySurveyRequest) GetAdditionalIssuesDescription() string {
|
||||
if x != nil && x.AdditionalIssuesDescription != nil {
|
||||
return *x.AdditionalIssuesDescription
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *SubmitCallQualitySurveyRequest) GetDebugLogUrl() string {
|
||||
if x != nil && x.DebugLogUrl != nil {
|
||||
return *x.DebugLogUrl
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *SubmitCallQualitySurveyRequest) GetStartTimestamp() int64 {
|
||||
if x != nil {
|
||||
return x.StartTimestamp
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *SubmitCallQualitySurveyRequest) GetEndTimestamp() int64 {
|
||||
if x != nil {
|
||||
return x.EndTimestamp
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *SubmitCallQualitySurveyRequest) GetCallType() string {
|
||||
if x != nil {
|
||||
return x.CallType
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *SubmitCallQualitySurveyRequest) GetSuccess() bool {
|
||||
if x != nil {
|
||||
return x.Success
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *SubmitCallQualitySurveyRequest) GetCallEndReason() string {
|
||||
if x != nil {
|
||||
return x.CallEndReason
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *SubmitCallQualitySurveyRequest) GetConnectionRttMedian() float32 {
|
||||
if x != nil && x.ConnectionRttMedian != nil {
|
||||
return *x.ConnectionRttMedian
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *SubmitCallQualitySurveyRequest) GetAudioRttMedian() float32 {
|
||||
if x != nil && x.AudioRttMedian != nil {
|
||||
return *x.AudioRttMedian
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *SubmitCallQualitySurveyRequest) GetVideoRttMedian() float32 {
|
||||
if x != nil && x.VideoRttMedian != nil {
|
||||
return *x.VideoRttMedian
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *SubmitCallQualitySurveyRequest) GetAudioRecvJitterMedian() float32 {
|
||||
if x != nil && x.AudioRecvJitterMedian != nil {
|
||||
return *x.AudioRecvJitterMedian
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *SubmitCallQualitySurveyRequest) GetVideoRecvJitterMedian() float32 {
|
||||
if x != nil && x.VideoRecvJitterMedian != nil {
|
||||
return *x.VideoRecvJitterMedian
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *SubmitCallQualitySurveyRequest) GetAudioSendJitterMedian() float32 {
|
||||
if x != nil && x.AudioSendJitterMedian != nil {
|
||||
return *x.AudioSendJitterMedian
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *SubmitCallQualitySurveyRequest) GetVideoSendJitterMedian() float32 {
|
||||
if x != nil && x.VideoSendJitterMedian != nil {
|
||||
return *x.VideoSendJitterMedian
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *SubmitCallQualitySurveyRequest) GetAudioRecvPacketLossFraction() float32 {
|
||||
if x != nil && x.AudioRecvPacketLossFraction != nil {
|
||||
return *x.AudioRecvPacketLossFraction
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *SubmitCallQualitySurveyRequest) GetVideoRecvPacketLossFraction() float32 {
|
||||
if x != nil && x.VideoRecvPacketLossFraction != nil {
|
||||
return *x.VideoRecvPacketLossFraction
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *SubmitCallQualitySurveyRequest) GetAudioSendPacketLossFraction() float32 {
|
||||
if x != nil && x.AudioSendPacketLossFraction != nil {
|
||||
return *x.AudioSendPacketLossFraction
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *SubmitCallQualitySurveyRequest) GetVideoSendPacketLossFraction() float32 {
|
||||
if x != nil && x.VideoSendPacketLossFraction != nil {
|
||||
return *x.VideoSendPacketLossFraction
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *SubmitCallQualitySurveyRequest) GetCallTelemetry() []byte {
|
||||
if x != nil {
|
||||
return x.CallTelemetry
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *SubmitCallQualitySurveyRequest) GetCallIdHash() []byte {
|
||||
if x != nil {
|
||||
return x.CallIdHash
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type SubmitCallQualitySurveyResponse struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *SubmitCallQualitySurveyResponse) Reset() {
|
||||
*x = SubmitCallQualitySurveyResponse{}
|
||||
mi := &file_org_signal_chat_call_quality_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *SubmitCallQualitySurveyResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*SubmitCallQualitySurveyResponse) ProtoMessage() {}
|
||||
|
||||
func (x *SubmitCallQualitySurveyResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_org_signal_chat_call_quality_proto_msgTypes[1]
|
||||
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 SubmitCallQualitySurveyResponse.ProtoReflect.Descriptor instead.
|
||||
func (*SubmitCallQualitySurveyResponse) Descriptor() ([]byte, []int) {
|
||||
return file_org_signal_chat_call_quality_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
var File_org_signal_chat_call_quality_proto protoreflect.FileDescriptor
|
||||
|
||||
const file_org_signal_chat_call_quality_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"\"org/signal/chat/call_quality.proto\x12\x1forg.signal.chat.calling.quality\x1a\x1dorg/signal/chat/require.proto\"\xc4\f\n" +
|
||||
"\x1eSubmitCallQualitySurveyRequest\x12%\n" +
|
||||
"\x0euser_satisfied\x18\x01 \x01(\bR\ruserSatisfied\x12.\n" +
|
||||
"\x13call_quality_issues\x18\x02 \x03(\tR\x11callQualityIssues\x12G\n" +
|
||||
"\x1dadditional_issues_description\x18\x03 \x01(\tH\x00R\x1badditionalIssuesDescription\x88\x01\x01\x12'\n" +
|
||||
"\rdebug_log_url\x18\x04 \x01(\tH\x01R\vdebugLogUrl\x88\x01\x01\x12'\n" +
|
||||
"\x0fstart_timestamp\x18\x05 \x01(\x03R\x0estartTimestamp\x12#\n" +
|
||||
"\rend_timestamp\x18\x06 \x01(\x03R\fendTimestamp\x12\x1b\n" +
|
||||
"\tcall_type\x18\a \x01(\tR\bcallType\x12\x18\n" +
|
||||
"\asuccess\x18\b \x01(\bR\asuccess\x12&\n" +
|
||||
"\x0fcall_end_reason\x18\t \x01(\tR\rcallEndReason\x127\n" +
|
||||
"\x15connection_rtt_median\x18\n" +
|
||||
" \x01(\x02H\x02R\x13connectionRttMedian\x88\x01\x01\x12-\n" +
|
||||
"\x10audio_rtt_median\x18\v \x01(\x02H\x03R\x0eaudioRttMedian\x88\x01\x01\x12-\n" +
|
||||
"\x10video_rtt_median\x18\f \x01(\x02H\x04R\x0evideoRttMedian\x88\x01\x01\x12<\n" +
|
||||
"\x18audio_recv_jitter_median\x18\r \x01(\x02H\x05R\x15audioRecvJitterMedian\x88\x01\x01\x12<\n" +
|
||||
"\x18video_recv_jitter_median\x18\x0e \x01(\x02H\x06R\x15videoRecvJitterMedian\x88\x01\x01\x12<\n" +
|
||||
"\x18audio_send_jitter_median\x18\x0f \x01(\x02H\aR\x15audioSendJitterMedian\x88\x01\x01\x12<\n" +
|
||||
"\x18video_send_jitter_median\x18\x10 \x01(\x02H\bR\x15videoSendJitterMedian\x88\x01\x01\x12I\n" +
|
||||
"\x1faudio_recv_packet_loss_fraction\x18\x11 \x01(\x02H\tR\x1baudioRecvPacketLossFraction\x88\x01\x01\x12I\n" +
|
||||
"\x1fvideo_recv_packet_loss_fraction\x18\x12 \x01(\x02H\n" +
|
||||
"R\x1bvideoRecvPacketLossFraction\x88\x01\x01\x12I\n" +
|
||||
"\x1faudio_send_packet_loss_fraction\x18\x13 \x01(\x02H\vR\x1baudioSendPacketLossFraction\x88\x01\x01\x12I\n" +
|
||||
"\x1fvideo_send_packet_loss_fraction\x18\x14 \x01(\x02H\fR\x1bvideoSendPacketLossFraction\x88\x01\x01\x12*\n" +
|
||||
"\x0ecall_telemetry\x18\x15 \x01(\fH\rR\rcallTelemetry\x88\x01\x01\x12%\n" +
|
||||
"\fcall_id_hash\x18\x16 \x01(\fH\x0eR\n" +
|
||||
"callIdHash\x88\x01\x01B \n" +
|
||||
"\x1e_additional_issues_descriptionB\x10\n" +
|
||||
"\x0e_debug_log_urlB\x18\n" +
|
||||
"\x16_connection_rtt_medianB\x13\n" +
|
||||
"\x11_audio_rtt_medianB\x13\n" +
|
||||
"\x11_video_rtt_medianB\x1b\n" +
|
||||
"\x19_audio_recv_jitter_medianB\x1b\n" +
|
||||
"\x19_video_recv_jitter_medianB\x1b\n" +
|
||||
"\x19_audio_send_jitter_medianB\x1b\n" +
|
||||
"\x19_video_send_jitter_medianB\"\n" +
|
||||
" _audio_recv_packet_loss_fractionB\"\n" +
|
||||
" _video_recv_packet_loss_fractionB\"\n" +
|
||||
" _audio_send_packet_loss_fractionB\"\n" +
|
||||
" _video_send_packet_loss_fractionB\x11\n" +
|
||||
"\x0f_call_telemetryB\x0f\n" +
|
||||
"\r_call_id_hash\"!\n" +
|
||||
"\x1fSubmitCallQualitySurveyResponse2\xb4\x01\n" +
|
||||
"\vCallQuality\x12\x9e\x01\n" +
|
||||
"\x17SubmitCallQualitySurvey\x12?.org.signal.chat.calling.quality.SubmitCallQualitySurveyRequest\x1a@.org.signal.chat.calling.quality.SubmitCallQualitySurveyResponse\"\x00\x1a\x04\xc8\xd5\"\x02B\x02P\x01b\x06proto3"
|
||||
|
||||
var (
|
||||
file_org_signal_chat_call_quality_proto_rawDescOnce sync.Once
|
||||
file_org_signal_chat_call_quality_proto_rawDescData []byte
|
||||
)
|
||||
|
||||
func file_org_signal_chat_call_quality_proto_rawDescGZIP() []byte {
|
||||
file_org_signal_chat_call_quality_proto_rawDescOnce.Do(func() {
|
||||
file_org_signal_chat_call_quality_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_org_signal_chat_call_quality_proto_rawDesc), len(file_org_signal_chat_call_quality_proto_rawDesc)))
|
||||
})
|
||||
return file_org_signal_chat_call_quality_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_org_signal_chat_call_quality_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
||||
var file_org_signal_chat_call_quality_proto_goTypes = []any{
|
||||
(*SubmitCallQualitySurveyRequest)(nil), // 0: org.signal.chat.calling.quality.SubmitCallQualitySurveyRequest
|
||||
(*SubmitCallQualitySurveyResponse)(nil), // 1: org.signal.chat.calling.quality.SubmitCallQualitySurveyResponse
|
||||
}
|
||||
var file_org_signal_chat_call_quality_proto_depIdxs = []int32{
|
||||
0, // 0: org.signal.chat.calling.quality.CallQuality.SubmitCallQualitySurvey:input_type -> org.signal.chat.calling.quality.SubmitCallQualitySurveyRequest
|
||||
1, // 1: org.signal.chat.calling.quality.CallQuality.SubmitCallQualitySurvey:output_type -> org.signal.chat.calling.quality.SubmitCallQualitySurveyResponse
|
||||
1, // [1:2] is the sub-list for method output_type
|
||||
0, // [0:1] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_org_signal_chat_call_quality_proto_init() }
|
||||
func file_org_signal_chat_call_quality_proto_init() {
|
||||
if File_org_signal_chat_call_quality_proto != nil {
|
||||
return
|
||||
}
|
||||
file_org_signal_chat_call_quality_proto_msgTypes[0].OneofWrappers = []any{}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_org_signal_chat_call_quality_proto_rawDesc), len(file_org_signal_chat_call_quality_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 2,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
GoTypes: file_org_signal_chat_call_quality_proto_goTypes,
|
||||
DependencyIndexes: file_org_signal_chat_call_quality_proto_depIdxs,
|
||||
MessageInfos: file_org_signal_chat_call_quality_proto_msgTypes,
|
||||
}.Build()
|
||||
File_org_signal_chat_call_quality_proto = out.File
|
||||
file_org_signal_chat_call_quality_proto_goTypes = nil
|
||||
file_org_signal_chat_call_quality_proto_depIdxs = nil
|
||||
}
|
||||
131
pkg/signalmeow/protobuf/rpc/call_quality/call_quality_grpc.pb.go
generated
Normal file
131
pkg/signalmeow/protobuf/rpc/call_quality/call_quality_grpc.pb.go
generated
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
//
|
||||
// Copyright 2025 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.6.2
|
||||
// - protoc v7.34.1
|
||||
// source: org/signal/chat/call_quality.proto
|
||||
|
||||
package call_quality
|
||||
|
||||
import (
|
||||
context "context"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
// Requires gRPC-Go v1.64.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion9
|
||||
|
||||
const (
|
||||
CallQuality_SubmitCallQualitySurvey_FullMethodName = "/org.signal.chat.calling.quality.CallQuality/SubmitCallQualitySurvey"
|
||||
)
|
||||
|
||||
// CallQualityClient is the client API for CallQuality service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
//
|
||||
// Provides methods for submitting call quality surveys
|
||||
type CallQualityClient interface {
|
||||
// Submits a call quality survey response.
|
||||
SubmitCallQualitySurvey(ctx context.Context, in *SubmitCallQualitySurveyRequest, opts ...grpc.CallOption) (*SubmitCallQualitySurveyResponse, error)
|
||||
}
|
||||
|
||||
type callQualityClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewCallQualityClient(cc grpc.ClientConnInterface) CallQualityClient {
|
||||
return &callQualityClient{cc}
|
||||
}
|
||||
|
||||
func (c *callQualityClient) SubmitCallQualitySurvey(ctx context.Context, in *SubmitCallQualitySurveyRequest, opts ...grpc.CallOption) (*SubmitCallQualitySurveyResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(SubmitCallQualitySurveyResponse)
|
||||
err := c.cc.Invoke(ctx, CallQuality_SubmitCallQualitySurvey_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// CallQualityServer is the server API for CallQuality service.
|
||||
// All implementations must embed UnimplementedCallQualityServer
|
||||
// for forward compatibility.
|
||||
//
|
||||
// Provides methods for submitting call quality surveys
|
||||
type CallQualityServer interface {
|
||||
// Submits a call quality survey response.
|
||||
SubmitCallQualitySurvey(context.Context, *SubmitCallQualitySurveyRequest) (*SubmitCallQualitySurveyResponse, error)
|
||||
mustEmbedUnimplementedCallQualityServer()
|
||||
}
|
||||
|
||||
// UnimplementedCallQualityServer must be embedded to have
|
||||
// forward compatible implementations.
|
||||
//
|
||||
// NOTE: this should be embedded by value instead of pointer to avoid a nil
|
||||
// pointer dereference when methods are called.
|
||||
type UnimplementedCallQualityServer struct{}
|
||||
|
||||
func (UnimplementedCallQualityServer) SubmitCallQualitySurvey(context.Context, *SubmitCallQualitySurveyRequest) (*SubmitCallQualitySurveyResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method SubmitCallQualitySurvey not implemented")
|
||||
}
|
||||
func (UnimplementedCallQualityServer) mustEmbedUnimplementedCallQualityServer() {}
|
||||
func (UnimplementedCallQualityServer) testEmbeddedByValue() {}
|
||||
|
||||
// UnsafeCallQualityServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to CallQualityServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeCallQualityServer interface {
|
||||
mustEmbedUnimplementedCallQualityServer()
|
||||
}
|
||||
|
||||
func RegisterCallQualityServer(s grpc.ServiceRegistrar, srv CallQualityServer) {
|
||||
// If the following call panics, it indicates UnimplementedCallQualityServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
|
||||
t.testEmbeddedByValue()
|
||||
}
|
||||
s.RegisterService(&CallQuality_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _CallQuality_SubmitCallQualitySurvey_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(SubmitCallQualitySurveyRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(CallQualityServer).SubmitCallQualitySurvey(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: CallQuality_SubmitCallQualitySurvey_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(CallQualityServer).SubmitCallQualitySurvey(ctx, req.(*SubmitCallQualitySurveyRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// CallQuality_ServiceDesc is the grpc.ServiceDesc for CallQuality service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var CallQuality_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "org.signal.chat.calling.quality.CallQuality",
|
||||
HandlerType: (*CallQualityServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "SubmitCallQualitySurvey",
|
||||
Handler: _CallQuality_SubmitCallQualitySurvey_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "org/signal/chat/call_quality.proto",
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue